springboot 缓存支持(二)注解配置与 redis 配合使用
虽然EhCache已经能够适用很多应用场景,但是由于EhCache是进程内的缓存框架,在集群模式下时,各应用服务器之间的缓存都是独立的,因此在不同服务器的进程间会存在缓存不一致的情况。即使EhCache提供了集群环境下的缓存同步策略,但是同步依然需要一定的时间,短暂的缓存不一致依然存在
Redis有三个主要特点,使它优越于其它键值数据存储系统 -
- Redis将其数据库完全保存在内存中,仅使用磁盘进行持久化。
- 与其它键值数据存储相比,Redis有一组相对丰富的数据类型。
- Redis可以将数据复制到任意数量的从机中。
1:加入依赖
2:配置文件信息
# REDIS (RedisProperties) # Redis数据库索引(默认为0) spring.redis.database=0 # Redis服务器地址 spring.redis.host=localhost # Redis服务器连接端口 spring.redis.port=6379 # Redis服务器连接密码(默认为空) spring.redis.password= # 连接池最大连接数(使用负值表示没有限制) redis.pool.max-active=8 # 连接池最大阻塞等待时间(使用负值表示没有限制) redis.pool.max-wait=-1 # 连接池中的最大空闲连接 redis.pool.max-idle=8 # 连接池中的最小空闲连接 redis.pool.min-idle=0 # 连接超时时间(毫秒) redis.timeout=0
3:配置config
@Configuration public class RedisConfig { // // @Bean // public RedisTemplate redisTemplate(RedisConnectionFactory connectionFactory) { // RedisTemplate template = new RedisTemplate<>(); // template.setConnectionFactory(connectionFactory); // // //使用Jackson2JsonRedisSerializer来序列化和反序列化redis的value值 // Jackson2JsonRedisSerializer serializer = new Jackson2JsonRedisSerializer(Object.class); // ObjectMapper mapper = new ObjectMapper(); // mapper.setVisibility( PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY); // mapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL); // serializer.setObjectMapper(mapper); // template.setValueSerializer(serializer); // // //使用StringRedisSerializer来序列化和反序列化redis的key值 // template.setKeySerializer(new StringRedisSerializer()); // template.afterPropertiesSet(); // return template; // } @Bean JedisConnectionFactory jedisConnectionFactory() { return new JedisConnectionFactory(); } @Bean public RedisTemplate redisTemplate() { RedisTemplate template = new RedisTemplate(); // template.setConnectionFactory(factory); template.setConnectionFactory(jedisConnectionFactory()); template.setKeySerializer(new StringRedisSerializer()); template.setValueSerializer(new RedisObjectSerializer()); return template; }
@Bean public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) { RedisTemplate<Object, Object> redisTemplate = new RedisTemplate<>(); redisTemplate.setConnectionFactory(redisConnectionFactory); // 使用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); // 设置value的序列化规则和 key的序列化规则 redisTemplate.setValueSerializer(jackson2JsonRedisSerializer); redisTemplate.setKeySerializer(new StringRedisSerializer()); redisTemplate.setHashKeySerializer(jackson2JsonRedisSerializer); redisTemplate.setHashValueSerializer(jackson2JsonRedisSerializer); redisTemplate.setDefaultSerializer(jackson2JsonRedisSerializer); redisTemplate.setEnableDefaultSerializer(true); redisTemplate.afterPropertiesSet(); return redisTemplate; }
4:注解方式实现缓存
实例化对象
* * 实例化对象 */ public class RedisObjectSerializer implements RedisSerializer<Object> { private Converter<Object, byte[]> serializer = new SerializingConverter(); private Converter<byte[], Object> deserializer = new DeserializingConverter(); static final byte[] EMPTY_ARRAY = new byte[0]; @Override public Object deserialize(byte[] bytes) { if (isEmpty(bytes)) { return null; } try { return deserializer.convert(bytes); } catch (Exception ex) { throw new SerializationException("Cannot deserialize", ex); } } @Override public byte[] serialize(Object object) { if (object == null) { return EMPTY_ARRAY; } try { return serializer.convert(object); } catch (Exception ex) { return EMPTY_ARRAY; } } private boolean isEmpty(byte[] data) { return (data == null || data.length == 0); } }
/** *根据name和id查询 * @param name * @param sex * @return * * @Cacheable 应用到读取数据的方法上, * 先从缓存中读取,如果没有再从DB获取数据,然后把数据添加到缓存中 * value 非必填。用于注定缓存数据的储存集合名称 * unless 表示条件表达式成立的话不放入缓存 */ @Cacheable(value = "user", key = "#sex + #name", unless = "#result eq null") public UserEntity finaUserByNAME(String name , int sex) { return userJpa.findUserEntityByNameAndSex( name,sex ); } /** * 新增用户 * @param userEntity * @return * @CachePut 应用到写数据的方法上,如新增/修改方法,调用方法时会自动把相应的数据放入缓存 */ @CachePut(value = "user",key = "#userEntity.getName()+'add'") public UserEntity add(UserEntity userEntity) { System.out.println(userEntity); return userJpa.save( userEntity ); } /** *删除 * @return * @CacheEvict 应用到删除数据的方法上,调用方法时会从缓存中删除对应key的数据 * 会删除名称为“user”的集合对象 */ @CacheEvict(value = "user", key = "'66redis'", condition = "#result eq true") public boolean delete(Integer id) { return userJpa.deleteUser( id )>0; }
6:controller层进行实例测试
@RestController @RequestMapping(value = "user") public class UserController { Logger logger = LoggerFactory.getLogger( UserService.class ); @Autowired private UserService userService; /** * 查询用户列表 * @return */ @GetMapping(value = "/all") @ResponseBody public List<UserEntity> list() { return userService.findAll( 9L ); } /** * 查询 * @param * @param * @return */ @PostMapping(value = "/nameandsex") @ResponseBody public UserEntity findUserByName(@RequestBody(required = false) RequestMode requestMode) { return userService.finaUserByNAME( requestMode.getName(),requestMode.getSex() ); } /** * 查询用户列表 * @return */ @PostMapping(value = "find") @ResponseBody public UserEntity listjj(@RequestBody(required = false) RequestMode requestMode) { return userService.finaUserByNAME1(requestMode.getName()); } /** * 添加用户 * @return */ @PostMapping(value = "add") @ResponseBody public UserEntity add() { UserEntity userEntity = new UserEntity( ); userEntity.setAddress( "淘宝" ); userEntity.setName( "redis" ); userEntity.setSex( 66 ); System.out.println(userEntity); return userService.add(userEntity); }
7:用posyman测试