Spring Cache集成redis的运行原理:
Spring缓存抽象模块通过CacheManager来创建、管理实际缓存组件,当SpringBoot应用程序引入spring-boot-starter-data-redi依赖后吗,容器中将注册的是CacheManager实例RedisCacheManager对象,RedisCacheManager来负责创建RedisCache作为缓存管理组件,由RedisCache操作redis服务器实现缓存数据操作。实际测试发现默认注入的RedisCacheManager操作缓存用的是RedisTemplate<Object, Object>,因此我们需要自定义cacheManager,替换掉默认的序列化器。
实现代码:
添加mybatis和redis依赖:
<dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> <version>1.3.2</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency>
添加mapper映射:
1 @Mapper 2 public interface ProductMapper { 3 @Select("select * from tb_product where product_id=#{id}") 4 Product getProductById(Long id); 5 6 @Update("update tb_product set product_name=#{productName},product_desc=#{productDesc} WHERE product_id=#{productId}") 7 int updateProduct(Product product); 8 9 @Delete("delete from tb_product where product_id=#{id}") 10 void deleteProductById(Long id); 11 12 @Select("select * from tb_product where product_name=#{productName}") 13 Product getProductByName(String productName); 14 }
Service:
1 package com.sl.cache.service; 2 import com.sl.cache.entity.Product; 3 import com.sl.cache.mapper.ProductMapper; 4 import org.springframework.beans.factory.annotation.Autowired; 5 import org.springframework.cache.annotation.CacheConfig; 6 import org.springframework.cache.annotation.CacheEvict; 7 import org.springframework.cache.annotation.CachePut; 8 import org.springframework.cache.annotation.Cacheable; 9 import org.springframework.cache.annotation.Caching; 10 import org.springframework.stereotype.Service; 11 12 @Service 13 @CacheConfig(cacheNames = "product") 14 public class ProductService { 15 @Autowired 16 private ProductMapper productMapper; 17 18 @Cacheable(cacheNames = "product1",key = "#root.methodName+'['+#id+']'") 19 //@Cacheable(cacheNames = {"product1","product2"})// 默认key为参数,多个参数SimpleKey [arg1,arg2] 20 //@Cacheable(cacheNames = "product",key = "#root.methodName+'['+#id+']'") 21 //@Cacheable(cacheNames = "product",keyGenerator = "myKeyGenerator") 22 //@Cacheable(cacheNames = "product",key = "#root.methodName+'['+#id+']'",condition="#a0>10",unless = "#a0==11") //或者condition="#id>10") 23 public Product getProductById(Long id){ 24 Product product =productMapper.getProductById(id); 25 System.out.println(product); 26 return product; 27 } 28 29 @CachePut(value="product",key = "#result.productId",condition = "#result!=null") 30 public Product updateProduct(Product product){ 31 int count = productMapper.updateProduct(product); 32 System.out.println("影响行数:"+count); 33 if(count>0){ 34 return product; 35 }else{ 36 return null; 37 } 38 } 39 40 //@CacheEvict(value="product",key="#id") 41 //@CacheEvict(value="product",allEntries = true) //清楚所有缓存 42 @CacheEvict(value="product",allEntries = true,beforeInvocation = true) //清楚所有缓存 43 public boolean deleteProductById(Long id) { 44 productMapper.deleteProductById(id); 45 return true; 46 } 47 48 //含有CachePut注解,所以执行这个方法时一定会查询数据库,及时有cacheable注解 49 @Caching( 50 cacheable = {@Cacheable(value="product",key="#productName")}, 51 put = { 52 @CachePut(value="product",key="#result.productId"), 53 @CachePut(value="product",key="#result.productName") 54 } 55 ) 56 public Product getProductByName(String productName){ 57 58 Product product =productMapper.getProductByName(productName); 59 60 return product; 61 } 62 }
Controller:
package com.sl.cache.controller; import com.sl.cache.entity.Product; import com.sl.cache.service.ProductService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.springframework.stereotype.Service; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; @RestController public class ProductController { @Autowired private ProductService productService; @GetMapping("/product/{id}") public Product getProduct(@PathVariable("id") Long id) { Product product = productService.getProductById(id); return product; } //prooduct?productid=1&productName= & @GetMapping("/product") public Product updateProduct(Product product) { productService.updateProduct(product); return product; } @GetMapping("/delproduct") public String delProduct(@RequestParam(value="id") Long id) { productService.deleteProductById(id); return "ok"; } @GetMapping("/product/name/{productName}") public Product getEmpByLastName(@PathVariable("productName") String productName){ return productService.getProductByName(productName); } }
自定义cacheManager实现:
1 package com.sl.cache.config; 2 import com.sl.cache.entity.Product; 3 import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; 4 import org.springframework.cache.CacheManager; 5 import org.springframework.cache.config.CacheManagementConfigUtils; 6 import org.springframework.context.annotation.Bean; 7 import org.springframework.context.annotation.Configuration; 8 import org.springframework.context.annotation.Primary; 9 import org.springframework.data.redis.cache.RedisCacheConfiguration; 10 import org.springframework.data.redis.cache.RedisCacheManager; 11 import org.springframework.data.redis.cache.RedisCacheWriter; 12 import org.springframework.data.redis.connection.RedisConnectionFactory; 13 import org.springframework.data.redis.core.RedisTemplate; 14 import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer; 15 import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer; 16 import org.springframework.data.redis.serializer.RedisSerializationContext; 17 import org.springframework.data.redis.serializer.RedisSerializer; 18 import org.springframework.data.redis.serializer.StringRedisSerializer; 19 20 import java.net.UnknownHostException; 21 import java.time.Duration; 22 23 @Configuration 24 public class MyRedisConfig { 25 26 @Bean(name = "redisTemplate") 27 public RedisTemplate<String,Object> redisTemplate(RedisConnectionFactory redisConnectionFactory){ 28 29 RedisTemplate<String,Object> redisTemplate = new RedisTemplate<>(); 30 31 redisTemplate.setConnectionFactory(redisConnectionFactory); 32 redisTemplate.setKeySerializer(keySerializer()); 33 redisTemplate.setHashKeySerializer(keySerializer()); 34 redisTemplate.setValueSerializer(valueSerializer()); 35 redisTemplate.setHashValueSerializer(valueSerializer()); 36 return redisTemplate; 37 } 38 39 @Primary 40 @Bean 41 public CacheManager cacheManager(RedisConnectionFactory redisConnectionFactory){ 42 //缓存配置对象 43 RedisCacheConfiguration redisCacheConfiguration = RedisCacheConfiguration.defaultCacheConfig(); 44 45 redisCacheConfiguration = redisCacheConfiguration.entryTtl(Duration.ofMinutes(30L)) //设置缓存的默认超时时间:30分钟 46 .disableCachingNullValues() //如果是空值,不缓存 47 .serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(keySerializer())) //设置key序列化器 48 .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer((valueSerializer()))); //设置value序列化器 49 50 return RedisCacheManager 51 .builder(RedisCacheWriter.nonLockingRedisCacheWriter(redisConnectionFactory)) 52 .cacheDefaults(redisCacheConfiguration).build(); 53 } 54 private RedisSerializer<String> keySerializer() { 55 return new StringRedisSerializer(); 56 } 57 58 private RedisSerializer<Object> valueSerializer() { 59 return new GenericJackson2JsonRedisSerializer(); 60 } 61 }
启用缓存,添加mybatis Mapper映射扫描:
1 @MapperScan("com.sl.cache.mapper") 2 @SpringBootApplication 3 @EnableCaching 4 public class SpringbootCacheApplication { 5 6 public static void main(String[] args) { 7 SpringApplication.run(SpringbootCacheApplication.class, args); 8 9 } 10 }