Spring全家桶笔记:非关系型数据库

Spring全家桶笔记:非关系型数据库

非关系型数据库概述

NoSQL(Not Only SQL)数据库是非关系型数据库的统称,主要分为以下几类:

  • 键值存储:Redis、Memcached
  • 文档数据库:MongoDB、Elasticsearch
  • 列式数据库:HBase、Cassandra
  • 图形数据库:Neo4j

Redis集成

Redis数据结构

类型 说明 典型应用
String 字符串 缓存、计数器
List 列表 消息队列
Hash 哈希 对象存储
Set 集合 标签、好友
ZSet 有序集合 排行榜

Spring Data Redis

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
@Configuration
public class RedisConfig {

@Bean
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory connectionFactory) {
RedisTemplate<String, Object> template = new RedisTemplate<>();
template.setConnectionFactory(connectionFactory);

// 使用Jackson2JsonRedisSerializer序列化
Jackson2JsonRedisSerializer<Object> serializer =
new Jackson2JsonRedisSerializer<>(Object.class);
template.setKeySerializer(new StringRedisSerializer());
template.setValueSerializer(serializer);
template.setHashKeySerializer(new StringRedisSerializer());
template.setHashValueSerializer(serializer);

return template;
}
}

基本操作

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
@Service
public class UserCacheService {

@Autowired
private RedisTemplate<String, Object> redisTemplate;

// String操作
public void set(String key, Object value) {
redisTemplate.opsForValue().set(key, value);
}

public Object get(String key) {
return redisTemplate.opsForValue().get(key);
}

// Hash操作
public void hSet(String key, String field, Object value) {
redisTemplate.opsForHash().put(key, field, value);
}

public Object hGet(String key, String field) {
return redisTemplate.opsForHash().get(key, field);
}

// List操作
public void lPush(String key, Object value) {
redisTemplate.opsForList().leftPush(key, value);
}

public Object lPop(String key) {
return redisTemplate.opsForList().leftPop(key);
}
}

缓存注解

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
@Service
public class UserService {

@Cacheable(value = "user", key = "#id")
public User getUserById(Long id) {
return userDao.findById(id);
}

@CachePut(value = "user", key = "#user.id")
public User updateUser(User user) {
return userDao.save(user);
}

@CacheEvict(value = "user", key = "#id")
public void deleteUser(Long id) {}

@CacheEvict(value = "user", allEntries = true)
public void clearCache() {}
}

MongoDB集成

Spring Data MongoDB

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
@Entity
@Document(collection = "users")
public class User {

@Id
private String id;

@Field("username")
private String username;

private Integer age;

private Address address;
}

@Document
public class Address {
private String city;
private String province;
}

Repository

1
2
3
4
5
6
7
8
9
public interface UserRepository extends MongoRepository<User, String> {

User findByUsername(String username);

List<User> findByAgeGreaterThan(Integer age);

@Query("{ 'username': { $regex: ?0 } }")
List<User> findByUsernameRegex(String regex);
}

MongoTemplate

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
@Service
public class UserService {

@Autowired
private MongoTemplate mongoTemplate;

public User save(User user) {
return mongoTemplate.save(user);
}

public List<User> findByCondition(Query query) {
return mongoTemplate.find(query, User.class);
}

public void update(Update update, Query query) {
mongoTemplate.updateMulti(query, update, User.class);
}
}

Elasticsearch集成

Spring Data Elasticsearch

1
2
3
4
5
6
7
8
9
10
11
12
13
14
@Document(indexName = "product")
public class Product {

@Id
private String id;

@Field(type = FieldType.Text, analyzer = "ik_max_word")
private String name;

@Field(type = FieldType.Keyword)
private String category;

private BigDecimal price;
}

Repository

1
2
3
4
5
6
7
public interface ProductRepository extends ElasticsearchRepository<Product, String> {

List<Product> findByNameContaining(String name);

@Query("{\"match\": {\"name\": {\"query\": \"?0\"}}}")
List<Product> searchByName(String keyword);
}

缓存策略

缓存穿透

  • 问题:查询不存在的数据导致频繁查询数据库
  • 解决方案:布隆过滤器、空值缓存

缓存击穿

  • 问题:热点key失效时大量请求涌入
  • 解决方案:互斥锁、永不过期

缓存雪崩

  • 问题:大量key同时失效
  • 解决方案:随机过期时间、持久化

实际应用建议

  1. 根据业务场景选择合适的NoSQL
  2. 合理设计数据模型
  3. 做好容量规划
  4. 配置合理的过期策略
  5. 做好数据备份和恢复

总结

非关系型数据库在特定场景下有显著优势,Spring Data提供了统一的整合方式。选择时需要根据数据特点、查询模式、一致性要求等因素综合考虑。