SpringBoot缓存注解实现Redis序列化操作

#SpringBoot缓存注解@Cachable实现Redis缓存操作

方法1 直接操作RedisTemplate缓存数据
方法2 在方法上加@Cacheable注解来缓存数据(这里只讲该方法)

引入依赖配置

pom.xml引入Redis的starter,容器中默认保存的是RedisCacheManager。RedisCacheManager帮我们创建RedisCache,通过RedisCache操作Redis缓存数据。默认保存数据k/v 都是Object,使用默认的JDK序列化器。

<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>

CacheManager配置

引入注解@EnableCaching,增加CacheManager配置。实现缓存自定义序列化和设置过期时间20s。
设置序列化后返回的是新的RedisCacheConfiguration。

import org.springframework.cache.annotation.EnableCaching;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.connection.RedisConnectionFactory;

@Configuration
@EnableCaching
public class RedisConfig
{
	@Bean
	public RedisCacheManager redisCacheManager(RedisConnectionFactory connectionFactory) 
	{
	    RedisCacheWriter redisCacheWriter = RedisCacheWriter.nonLockingRedisCacheWriter(connectionFactory);
	    Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<>(Object.class);
	    RedisSerializationContext.SerializationPair<Object> serializationPair = RedisSerializationContext.SerializationPair.fromSerializer(jackson2JsonRedisSerializer);
	    RedisCacheConfiguration redisCacheConfiguration = RedisCacheConfiguration.defaultCacheConfig().entryTtl(Duration.ofSeconds(20)).serializeValuesWith(serializationPair);
	    return new RedisCacheManager(redisCacheWriter, redisCacheConfiguration); 
	}
	
	@Bean
	public RedisTemplate<String, Object> getRedisTemplate(RedisConnectionFactory connectionFactory) {
		// Redis对json序列化处理
		RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
		redisTemplate.setConnectionFactory(connectionFactory);
		// 使用Jackson2JsonRedisSerialize替换默认序列化方式
		Jackson2JsonRedisSerializer<?> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<>(Object.class);
		StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
		ObjectMapper om = new ObjectMapper();
		om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
		// 启用默认的类型
		om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
		// 序列化类,对象映射设置
		jackson2JsonRedisSerializer.setObjectMapper(om);
		redisTemplate.setKeySerializer(stringRedisSerializer);
		redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);
		redisTemplate.setHashKeySerializer(stringRedisSerializer);
		redisTemplate.setHashValueSerializer(jackson2JsonRedisSerializer);
		redisTemplate.afterPropertiesSet();
	}
}

Controller层

@RestController
public class RedisController 
{
	@RequestMapping(value="cache/{id}")
	public void cache(@PathVariable String id)
	{
		System.out.println("【Controll】cache---" + id);
		this.redisService.cache(id);
	}
	
	@RequestMapping(value = "/addcache/{id}")
	public boolean add(@PathVariable String id) {
		Usr usr = new Usr();
		usr.id = id;
		usr.name = "Lyndon-" +id;
		usr.pwd = "123";
		this.redisService.addCache(usr);
		return true;
	}

	@RequestMapping(value = "/delcache/{id}")
	public void delByUuid(@PathVariable String id) {
		this.redisService.delCache(id);
	}
}

Service层

缓存注解在业务层

RedisService、RedisServiceImpl实现类

import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.CachePut;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.data.redis.core.RedisTemplate;

@Service
public class RedisServiceImpl implements RedisService
{
	static final String REDIS_VALUE = "user-";
    
	@Override
	@Cacheable(value = REDIS_VALUE, key = "getArgs()[0]") // 结果可缓存
    public User cache(String id){
        User user = new User();
        user.setId(id);
        user.setName("Lyndon-" + id);
        user.setPwd("123456");
        System.out.println("【SERVICE】cache:" + user);
        return user;
    }
   
	@Override
	@CachePut(value = REDIS_VALUE, key = "getArgs()[0].id") //加入缓存
	public Usr addCache(String id)
	{
		User user = new User();
		user.id = id;
		// this.redisTemplate.opsForSet().add(id, user);
		System.out.println("【SERVICE】add cache:" + user);
		return user;
	}
	
	@Override
	@CacheEvict(value = REDIS_VALUE, key = "getArgs()[0]") //删除缓存
    public void delCache(String id) {
    }
}

Cache注解说明

@Cacheable 在调用方法之前,先在缓存中查找方法的返回值,如果这个值能够找到,返回缓存的值。否则执行这个方法,将方法的返回值放到缓存之中。

spEL几种写法

@Cacheable(value = "user", key = "#root.method") //"user::public com.example.demo.User com.example.demo.UserServiceImpl.findcache(com.example.demo.User)"
@Cacheable(value = "user", key = "#root.method.name") //"user::findcache"
@Cacheable(value = "user", key = "#root.targetClass") // "user::class com.example.demo.UserServiceImpl"
@Cacheable(value = "user", key = "args[0]") //user对象
@Cacheable(value = "user", key = "args[0].id") //"user::1001", 相当于"#user.id"
@Cacheable(value = "user", key = "caches[0].name") //"user::user"
@Cacheable(value = "user", key = "#user.id") //"user::1001"
@Cacheable(value = {"user1","user2"}, key = "#pageIndex+'-'+(#pageIndex+#pageSize)") 


@Cacheable(value = {"dept_list"}, key = "#pageIndex+'-'+(#pageIndex+#pageSize)") //分页查询加入缓存
public List<Dept> queryDepts(String id, String name, int level, int pageIndex, int pageSize) {
	return this.deptDao.queryDepts(id, name, level, pageIndex, pageSize);
}

192.168.236.128:6379> keys *
1) "dept_list::40-60"
2) "dept_list::20-40"
3) "dept_list::0-20"

@CachePut 根据方法的请求参数对其结果进行缓存

@CacheEvict 根据条件对缓存进行清空
当缓存的实体更新后,get到的仍是旧的缓存。这时候就需要清除相关联的缓存。方法就是提供一个空的接口方法,在该方法上添加@CacheEvict的注解。
(也可使用定时任务实现缓存的自动清除功能。)

@CacheConfig(cacheNames = “user”)//类级别的缓存注解,允许共享缓存名称

@Caching 组合使用多个操作缓存的注解 evict={}中是用@CacheEvict 、 put={}中是用@CachePut 、 cacheable={}中是用

执行结果

执行三次查询:
第一次 进入Service方法,添加了值
第二次 不进入Service方法也得到了值
同理第三次

【Controll】cache:1001
【SERVICE】---User [id = 1001, name=Lyndon-1001, pwd=123456l]

【Controll]】cache:1001
【Controll]】cache:1001
【Controll]】cache:1001

Redis查询

[root@localhost Desktop]# redis-cli -c -h 192.168.236.128 -p 6379 -a 123456
192.168.236.128:6379> keys user-*
-> Redirected to slot [7252] located at 192.168.236.128:6382
1) "user-::1001"

# 序列化前
192.168.236.128:6382> get user-::1001
"\xac\xed\x00\x05sr\x00\x15com.example.demo.User\x00\x00\x00\x00\x00\x00\x00\x01\x02\x00\x05L\x00\x02idt\x00\x12Ljava/lang/String;L\x00\x05ltimet\x00\x10Ljava/util/Date;L\x00\x04nameq\x00~\x00\x01L\x00\x03pwdq\x00~\x00\x01L\x00\x05tokenq\x00~\x00\x01xpt\x00\x041001sr\x00\x0ejava.util.Datehj\x81\x01KYt\x19\x03\x00\x00xpw\b\x00\x00\x01m\x15\x84w\xd0xt\x00\x041001t\x00\x03123t\x00 7c86ab65f8394c0a8ba966f1ba53b04c"

# 序列化后
192.168.236.128:6382> get user-::1001
"[\"com.example.demo.User\",{\"id\":\"1001\",\"name\":\"1002\",\"pwd\":\"123\",\"ltime\":[\"java.util.Date\",1568024066000],\"token\":\"7c86ab65f8394c0a8ba966f1ba53b04c\"}]"

# 20秒后缓存消失
192.168.236.128:6382> get user-::1001
(nil)


总结

两种方式各不相同,一种是直接当成数据库调用形式,一种是通过注解的形式。
(方法1登录注册适用于缓存session、token等用户登录信息;方法2适用于缓存查询结果)

当然各有长短板,所以可以说,两种方式可以在项目中结合使用,但是缓存的时候不要互串,比如使用第二种方式创建的缓存在第一种方式获取,后面维护起来很痛苦。

参考资料

springboot与redis处理缓存
http://liweidan.cn/java/frame/spring-boot/2019/01/08/254/

springboot2.0自定义ReidsCacheManager的改变
https://www.jianshu.com/p/20366ecf12ce

Spring Boot之 Spring Boot + Cache + RedisTemplate整合
https://blog.csdn.net/jy02268879/article/details/83095559

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值