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<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; public void set(String key, Object value) { redisTemplate.opsForValue().set(key, value); } public Object get(String key) { return redisTemplate.opsForValue().get(key); } 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); } 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同时失效
- 解决方案:随机过期时间、持久化
实际应用建议
- 根据业务场景选择合适的NoSQL
- 合理设计数据模型
- 做好容量规划
- 配置合理的过期策略
- 做好数据备份和恢复
总结
非关系型数据库在特定场景下有显著优势,Spring Data提供了统一的整合方式。选择时需要根据数据特点、查询模式、一致性要求等因素综合考虑。