知识追寻者(Inheriting the spirit of open source, Spreading technology knowledge;)
pring为我们提供的缓存注解Spring Cache。Spring支持多种缓存技术:RedisCacheManager,EhCacheCacheManager、GuavaCacheManager等,今天的内容是集成RedisCacheManager实现缓存技术;
spring cache 常用注解如下
作用:查询数据加入缓存
参数如下:
作用:修改了数据库的数据,同时更新缓存。
参数如下:
作用:删除数据,删除缓存
参数如下:
springboot 2.1.1
<dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>1.16.18</version> <scope>provided</scope> </dependency> <dependency> <groupId>org.postgresql</groupId> <artifactId>postgresql</artifactId> <scope>runtime</scope> </dependency> <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> <version>1.3.0</version> </dependency> </dependencies> 复制代码
主要是 redis 和 数据库 链接配置;如果使用mysql 自行更好 数据库链接驱动和依赖;
server: port: 9000 spring: redis: # Redis服务器地址 host: localhost #Redis服务器连接端口 port: 6379 #password: # Redis数据库索引(默认为0) database: 2 # 连接超时时间(毫秒) timeout: 5000 jedis: pool: #连接池最大连接数(使用负值表示没有限制) max-active: 100 # 连接池中的最小空闲连接 max-idle: 10 # 连接池最大阻塞等待时间(使用负值表示没有限制) max-wait: 100000 #数据库配置 datasource: driverClassName: org.postgresql.Driver url: jdbc:postgresql://127.0.0.1:5432/springboot username: postgres password: 123456 logging: level: com.zszxz.cach.mapper : debug 复制代码
主要是设置 CacheManager
和 redisTemplate
; 并且支持默认key 过期时间,和乱码问题解决;
/** * @Author lsc * <p> redis配置 </p> */ @Configuration @EnableCaching public class RedisConfig extends CachingConfigurerSupport { /* * * @Author lsc * <p>自定义生成key的规则 </p> * @Param [] * @Return KeyGenerator */ @Override @Bean public KeyGenerator keyGenerator() { return new KeyGenerator() { @Override public Object generate(Object o, Method method, Object... objects) { //格式化缓存key字符串 StringBuilder sb = new StringBuilder(); //追加类名 sb.append(o.getClass().getName()); //追加方法名 sb.append(method.getName()); //遍历参数并且追加 for (Object obj : objects) { sb.append(obj.toString()); } return sb.toString(); } }; } @Bean public CacheManager cacheManager(RedisConnectionFactory factory) { RedisSerializer<String> redisSerializer = new StringRedisSerializer(); Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class); //解决查询缓存转换异常的问题 ObjectMapper om = new ObjectMapper(); om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY); om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL); jackson2JsonRedisSerializer.setObjectMapper(om); // 配置序列化(解决乱码的问题),过期时间120秒 RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig() .entryTtl(Duration.ofSeconds(120)) .serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(redisSerializer)) .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(jackson2JsonRedisSerializer)) .disableCachingNullValues(); RedisCacheManager cacheManager = RedisCacheManager.builder(factory) .cacheDefaults(config) .build(); return cacheManager; } @Bean public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory connectionFactory) { // 创建redisTemplate RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>(); redisTemplate.setConnectionFactory(connectionFactory); // 使用Jackson2JsonRedisSerialize替换默认序列化 Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class); ObjectMapper objectMapper = new ObjectMapper(); objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY); objectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL); jackson2JsonRedisSerializer.setObjectMapper(objectMapper); //set value serializer redisTemplate.setDefaultSerializer(jackson2JsonRedisSerializer); // key采用String的序列化方式 redisTemplate.setKeySerializer(new StringRedisSerializer()); // value序列化方式采用jackson redisTemplate.setValueSerializer(jackson2JsonRedisSerializer); // hash的key也采用String的序列化方式 redisTemplate.setHashKeySerializer(new StringRedisSerializer()); // hash的value序列化方式采用jackson redisTemplate.setHashValueSerializer(jackson2JsonRedisSerializer); redisTemplate.afterPropertiesSet(); return redisTemplate; } } 复制代码
/* * * @Author lsc * <p>先从缓存中读取,如果没有再从DB获取数据,然后把数据添加到缓存中 * unless 表示条件表达式成立的话不放入缓存 * 如果 设置 ,keyGenerator = "keyGenerator" 就不能设置 key * </p> * @Param [user_id] * @Return com.zszxz.cach.entity.UserEntity */ @Override @Cacheable(cacheNames = "UserEntity", key = "#user_id") public UserEntity getUser(Long user_id) { return userMapper.getUser(user_id); } /* * * @Author lsc * <p>修改了数据库的数据,同时更新缓存。先调用目标方法,然后缓存方法结果 </p> * @Param [userEntity] * @Return int */ @Override @CachePut(cacheNames = "UserEntity", key = "#result.user_id") public UserEntity updateUser(UserEntity userEntity) { userMapper.updateUser(userEntity); // 注意,会将缓存更新未参数userEntity里面的值 return userEntity; } /* * * @Author lsc * <p>allEntries 是否清空所有缓存内容,缺省为 false,如果指定为 true,则方法调用后将立即清空所有缓存 * 指定删除一条缓存 * </p> * @Param [user_id] * @Return int */ @Override @CacheEvict(cacheNames = "UserEntity", key = "#user_id") public int delUser(Long user_id) { return userMapper.delUser(user_id); } 复制代码
测试代码
@Test public void testGet(){ UserEntity user = userService.getUser(1L); System.out.println(user); } 复制代码
第一次查询控制台会打印SQL,第二次查询不会打印SQL,直接从redis获取
修改缓存的结果是方法的返回值,由于这边式参数直接作为返回值,故参数用户实体的属性必须是全属性,否则查询缓存时会出现多个参数是null,而数据库中有值;比如这边的user_telephone字段;
@Test public void testPUT(){ UserEntity userEntity = new UserEntity(); userEntity.setUser_id(1L); userEntity.setUser_name("知识追寻者"); userEntity.setUser_gender("female"); userService.updateUser(userEntity); } 复制代码