资讯动态

Spring Boot 与 Redis 缓存集成实战:构建高性能缓存系统

发布时间:2026/8/24 6:23:56 来源:尧图企业网站定制
Spring Boot 与 Redis 缓存集成实战构建高性能缓存系统一、引言在现代应用开发中缓存是提升系统性能的关键技术之一。Redis 作为一款高性能的键值存储数据库凭借其丰富的数据结构、强大的缓存能力和分布式特性已经成为业界最受欢迎的缓存解决方案之一。Spring Boot 提供了对 Redis 的原生支持通过 Spring Data Redis 和 Spring Cache 抽象开发者可以轻松地将 Redis 集成到应用中实现高效的数据缓存。本文将深入探讨 Spring Boot 与 Redis 缓存的集成实践包括环境配置、缓存注解使用、缓存策略设计以及缓存一致性保证等方面。二、环境准备与依赖配置2.1 依赖引入在pom.xml中添加 Redis 相关依赖dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-data-redis/artifactId /dependency dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-cache/artifactId /dependency dependency groupIdorg.apache.commons/groupId artifactIdcommons-pool2/artifactId /dependency2.2 配置文件设置在application.yml中配置 Redis 连接信息spring: redis: host: localhost port: 6379 password: database: 0 timeout: 10s lettuce: pool: max-active: 8 max-idle: 8 min-idle: 2 max-wait: 10000ms cache: type: redis redis: time-to-live: 60000ms cache-null-values: false2.3 Redis 配置类创建自定义的 Redis 配置Configuration EnableCaching public class RedisConfig { Bean public RedisTemplateString, Object redisTemplate( RedisConnectionFactory connectionFactory ) { RedisTemplateString, Object template new RedisTemplate(); template.setConnectionFactory(connectionFactory); Jackson2JsonRedisSerializerObject jsonSerializer new Jackson2JsonRedisSerializer(Object.class); ObjectMapper objectMapper new ObjectMapper(); objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY); objectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL); jsonSerializer.setObjectMapper(objectMapper); StringRedisSerializer stringSerializer new StringRedisSerializer(); template.setKeySerializer(stringSerializer); template.setHashKeySerializer(stringSerializer); template.setValueSerializer(jsonSerializer); template.setHashValueSerializer(jsonSerializer); template.afterPropertiesSet(); return template; } Bean public CacheManager cacheManager(RedisConnectionFactory connectionFactory) { RedisCacheConfiguration config RedisCacheConfiguration.defaultCacheConfig() .entryTtl(Duration.ofMinutes(10)) .serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer( new StringRedisSerializer())) .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer( new Jackson2JsonRedisSerializer(Object.class))); return RedisCacheManager.builder(connectionFactory) .cacheDefaults(config) .build(); } }三、缓存注解使用指南3.1 Cacheable 注解用于查询缓存如果缓存存在则直接返回否则执行方法并将结果存入缓存Service public class UserService { private final UserRepository userRepository; public UserService(UserRepository userRepository) { this.userRepository userRepository; } Cacheable(value users, key #id, unless #result null) public User getUserById(Long id) { return userRepository.findById(id).orElse(null); } Cacheable(value users, key #email, condition #email ! null) public User getUserByEmail(String email) { return userRepository.findByEmail(email); } }3.2 CachePut 注解用于更新缓存执行方法后将结果存入缓存CachePut(value users, key #user.id) public User updateUser(User user) { return userRepository.save(user); } CachePut(value users, key #result.id) public User createUser(User user) { return userRepository.save(user); }3.3 CacheEvict 注解用于删除缓存CacheEvict(value users, key #id) public void deleteUser(Long id) { userRepository.deleteById(id); } CacheEvict(value users, allEntries true) public void clearAllUsers() { userRepository.deleteAll(); }3.4 Caching 组合注解用于组合多个缓存操作Caching( put { CachePut(value users, key #user.id), CachePut(value users, key #user.email) }, evict { CacheEvict(value userList, allEntries true) } ) public User saveUser(User user) { return userRepository.save(user); }四、缓存策略设计4.1 缓存穿透解决方案缓存穿透是指查询一个不存在的数据导致每次请求都直接访问数据库。Service public class ProductService { private static final String NULL_VALUE NULL_VALUE; Cacheable(value products, key #id) public Product getProductById(Long id) { Product product productRepository.findById(id).orElse(null); if (product null) { throw new ProductNotFoundException(Product not found: id); } return product; } } ControllerAdvice public class CacheExceptionHandler { CachePut(value products, key #ex.id) public String handleProductNotFound(ProductNotFoundException ex) { return NULL_VALUE; } }更好的解决方案是使用空对象缓存Cacheable(value products, key #id) public Product getProductById(Long id) { Product product productRepository.findById(id).orElse(null); if (product null) { return new NullProduct(); } return product; }4.2 缓存击穿解决方案缓存击穿是指某个热点 key 在缓存过期时大量请求同时访问导致数据库压力过大。Service public class HotProductService { private final ReentrantLock lock new ReentrantLock(); Cacheable(value hotProducts, key #id) public Product getHotProduct(Long id) { return getProductFromDB(id); } private Product getProductFromDB(Long id) { if (lock.tryLock()) { try { Product product productRepository.findById(id).orElse(null); if (product ! null) { cacheManager.getCache(hotProducts).put(id, product); } return product; } finally { lock.unlock(); } } else { try { Thread.sleep(100); } catch (InterruptedException e) { Thread.currentThread().interrupt(); } return getHotProduct(id); } } }4.3 缓存雪崩解决方案缓存雪崩是指大量缓存同时过期导致所有请求都直接访问数据库。Configuration public class CacheConfig { Bean public CacheManager cacheManager(RedisConnectionFactory connectionFactory) { MapString, RedisCacheConfiguration cacheConfigurations new HashMap(); cacheConfigurations.put(users, RedisCacheConfiguration.defaultCacheConfig() .entryTtl(Duration.ofMinutes(10 new Random().nextInt(5)))); cacheConfigurations.put(products, RedisCacheConfiguration.defaultCacheConfig() .entryTtl(Duration.ofMinutes(15 new Random().nextInt(10)))); return RedisCacheManager.builder(connectionFactory) .withInitialCacheConfigurations(cacheConfigurations) .build(); } }五、分布式缓存一致性5.1 缓存与数据库一致性策略Service public class OrderService { Transactional CacheEvict(value orders, key #order.id) public Order createOrder(Order order) { Order saved orderRepository.save(order); cacheManager.getCache(orderStatistics).clear(); return saved; } Transactional Caching( evict { CacheEvict(value orders, key #id), CacheEvict(value orderItems, key #id) } ) public void cancelOrder(Long id) { orderRepository.deleteById(id); } }5.2 使用消息队列保证最终一致性Service public class ProductCacheService { private final RabbitTemplate rabbitTemplate; public ProductCacheService(RabbitTemplate rabbitTemplate) { this.rabbitTemplate rabbitTemplate; } Transactional public Product updateProduct(Product product) { Product saved productRepository.save(product); rabbitTemplate.convertAndSend(cache-update-exchange, product.update, product.getId()); return saved; } } Component public class CacheUpdateListener { RabbitListener(queues cache-update-queue) public void handleCacheUpdate(Long productId) { Product product productRepository.findById(productId).orElse(null); if (product ! null) { cacheManager.getCache(products).put(productId, product); } } }六、高级缓存操作6.1 缓存预热Component public class CacheWarmUp implements ApplicationRunner { private final UserRepository userRepository; private final CacheManager cacheManager; public CacheWarmUp(UserRepository userRepository, CacheManager cacheManager) { this.userRepository userRepository; this.cacheManager cacheManager; } Override public void run(ApplicationArguments args) { Cache usersCache cacheManager.getCache(users); ListUser users userRepository.findAll(); for (User user : users) { usersCache.put(user.getId(), user); } } }6.2 缓存统计与监控Service public class CacheStatisticsService { private final StringRedisTemplate stringRedisTemplate; public CacheStatisticsService(StringRedisTemplate stringRedisTemplate) { this.stringRedisTemplate stringRedisTemplate; } public MapString, Object getCacheStats(String cacheName) { MapString, Object stats new HashMap(); SetString keys stringRedisTemplate.keys(cacheName :*); stats.put(keyCount, keys ! null ? keys.size() : 0); return stats; } public void clearExpiredCache() { SetString allKeys stringRedisTemplate.keys(*); if (allKeys ! null) { for (String key : allKeys) { if (stringRedisTemplate.getExpire(key) -2) { stringRedisTemplate.delete(key); } } } } }6.3 缓存注解自定义Target({ElementType.METHOD, ElementType.TYPE}) Retention(RetentionPolicy.RUNTIME) Cacheable(cacheNames customCache) public interface CustomCache { String key() default ; String condition() default ; String unless() default ; }七、缓存实战案例7.1 用户服务缓存Service public class UserService { private final UserRepository userRepository; public UserService(UserRepository userRepository) { this.userRepository userRepository; } Cacheable(value users, key #id) public User getUserById(Long id) { return userRepository.findById(id).orElse(null); } Cacheable(value userByEmail, key #email) public User getUserByEmail(String email) { return userRepository.findByEmail(email); } CachePut(value {users, userByEmail}, key {#user.id, #user.email}) public User saveUser(User user) { return userRepository.save(user); } CacheEvict(value {users, userByEmail}, key {#id, #result.email}) public User deleteUser(Long id) { User user getUserById(id); if (user ! null) { userRepository.delete(user); } return user; } Cacheable(value userList, key #page - #size) public ListUser getUsers(int page, int size) { return userRepository.findAll(PageRequest.of(page, size)).getContent(); } }7.2 商品服务缓存Service public class ProductService { private final ProductRepository productRepository; public ProductService(ProductRepository productRepository) { this.productRepository productRepository; } Cacheable(value products, key #id) public Product getProductById(Long id) { return productRepository.findById(id).orElse(null); } Cacheable(value productsByCategory, key #category) public ListProduct getProductsByCategory(String category) { return productRepository.findByCategory(category); } Cacheable(value productList, key #page - #size) public PageProduct getProducts(int page, int size) { return productRepository.findAll(PageRequest.of(page, size)); } CachePut(value {products, productsByCategory}, key {#product.id, #product.category}) public Product updateProduct(Product product) { return productRepository.save(product); } CacheEvict(value {products, productsByCategory, productList}, key {#id, #result.category}, allEntries true) public Product deleteProduct(Long id) { Product product getProductById(id); if (product ! null) { productRepository.delete(product); } return product; } }八、缓存配置最佳实践8.1 缓存命名规范public class CacheNames { public static final String USERS users; public static final String PRODUCTS products; public static final String ORDERS orders; public static final String USER_BY_EMAIL userByEmail; public static final String PRODUCT_BY_CATEGORY productsByCategory; }8.2 缓存时间策略Configuration public class CacheTtlConfig { Bean public CacheManager cacheManager(RedisConnectionFactory connectionFactory) { MapString, RedisCacheConfiguration configs new HashMap(); configs.put(CacheNames.USERS, RedisCacheConfiguration.defaultCacheConfig() .entryTtl(Duration.ofMinutes(30))); configs.put(CacheNames.PRODUCTS, RedisCacheConfiguration.defaultCacheConfig() .entryTtl(Duration.ofHours(1))); configs.put(CacheNames.ORDERS, RedisCacheConfiguration.defaultCacheConfig() .entryTtl(Duration.ofMinutes(15))); return RedisCacheManager.builder(connectionFactory) .withInitialCacheConfigurations(configs) .build(); } }8.3 缓存监控配置Configuration public class CacheMetricsConfig { Bean public MeterRegistryCustomizerMeterRegistry cacheMetrics() { return registry - registry.config() .meterFilter(MeterFilter.denyNameStartsWith(jvm)); } }九、测试用例SpringBootTest class CacheIntegrationTest { Autowired private UserService userService; Autowired private CacheManager cacheManager; Test void testCacheable() { Long userId 1L; User user1 userService.getUserById(userId); assertNotNull(user1); User user2 userService.getUserById(userId); assertSame(user1, user2); } Test void testCachePut() { User user new User(); user.setName(Test User); user.setEmail(testexample.com); User saved userService.saveUser(user); assertNotNull(saved.getId()); Cache cache cacheManager.getCache(users); User cached cache.get(saved.getId(), User.class); assertNotNull(cached); assertEquals(Test User, cached.getName()); } Test void testCacheEvict() { Long userId 1L; userService.getUserById(userId); Cache cache cacheManager.getCache(users); assertNotNull(cache.get(userId)); userService.deleteUser(userId); assertNull(cache.get(userId)); } }十、总结本文详细介绍了 Spring Boot 与 Redis 缓存的集成实践涵盖了从基础配置到高级特性的各个方面环境配置依赖引入、连接配置、缓存管理器配置缓存注解Cacheable、CachePut、CacheEvict、Caching 的使用缓存策略缓存穿透、缓存击穿、缓存雪崩的解决方案一致性保证缓存与数据库的一致性策略高级特性缓存预热、缓存统计、自定义缓存注解通过本文的学习读者可以掌握 Spring Boot 与 Redis 缓存集成的核心技能能够构建高效、可靠的缓存系统。在实际项目中需要根据业务特点选择合适的缓存策略平衡性能与一致性的需求。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价