您的位置:首页 > 数据库 > Redis

使用spring-data-redis实现incr自增

2017-09-03 13:13 1001 查看

redis系列文章目录

使用spring-data-redis实现incr自增

Redis 利用Hash存储节约内存

Redis学习笔记(九)redis实现时时直播列表缓存,支持分页[热点数据存储]

Redis学习笔记(八)redis之lua脚本学习

Redis学习笔记(七)jedis超时重试机制注意事项

Redis学习笔记(六)redis实现分布式锁

Redis学习笔记(五)jedis(JedisCluster)操作Redis集群 redis-cluster

redis学习笔记(四)缓存与数据库一致性问题

redis学习笔记(三)数据淘汰策略

redis学习笔记(二)JedisCluster + redis 3.2.5集群

redis学习笔记(一)redis3.2.5集群安装与测试

应该有不少人在使用spring-data-redis时遇到各种各样的问题。反正我是遇到了。

由于是隔了一段时间才写的本篇博客,也懒得去重现哪些错误场景了,下面凭着记忆写了几个我遇到的问题:

redis.clients.jedis.exceptions.JedisDataException: ERR value is not an integer or out of range

使用的
RedisTemplate
,做读写操作时候,都是要经过序列化和反序列化。这时你使用
redisTemplate.opsForValue().increment()
就可能报错
redis.clients.jedis.exceptions.JedisDataException: ERR value is not an integer or out of range
了。

valueOper.get(key) 获取不到自增的值。

于是我去看了一下redis的官方文档,找到一个解决方法

使用spring-data-redis实现incr自增

/**
*
* @param key
* @param liveTime
* @return
*/
public Long incr(String key, long liveTime) {
RedisAtomicLong entityIdCounter = new RedisAtomicLong(key, redisTemplate.getConnectionFactory());
Long increment = entityIdCounter.getAndIncrement();

if ((null == increment || increment.longValue() == 0) && liveTime > 0) {//初始设置过期时间
entityIdCounter.expire(liveTime, TimeUnit.SECONDS);
}

return increment;
}


这样,上面的
increment
就是自增后的新知值,然后中间通过
entityIdCounter.expire(liveTime, TimeUnit.SECONDS);
设置过期时间。当然这里比较讨厌,spring没有在创建
RedisAtomicLong
对象的时候一起设置过期时间。可以看看其源码,
new RedisAtomicLong
最终调用的是这个方法:

private RedisAtomicLong(String redisCounter, RedisConnectionFactory factory, Long initialValue) {
Assert.hasText(redisCounter, "a valid counter name is required");
Assert.notNull(factory, "a valid factory is required");

RedisTemplate<String, Long> redisTemplate = new RedisTemplate<String, Long>();
redisTemplate.setKeySerializer(new StringRedisSerializer());
redisTemplate.setValueSerializer(new GenericToStringSerializer<Long>(Long.class));
redisTemplate.setExposeConnection(true);
redisTemplate.setConnectionFactory(factory);
redisTemplate.afterPropertiesSet();

this.key = redisCounter;
this.generalOps = redisTemplate;
this.operations = generalOps.opsForValue();

if (initialValue == null) {
if (this.operations.get(redisCounter) == null) {
set(0);
}
} else {
set(initialValue);
}
}


可以看到,初始值是0。

然后根进
set
方法

public void set(long newValue) {
operations.set(key, newValue);
}


可以看到,他是采用的
operations.set(key, newValue);
但是明明还有一个重载的方法
void set(K key, V value, long timeout, TimeUnit unit);
可以设置过期时间,为啥spring不提供呢。

为了解决这个问题,我们可以自己模拟
RedisAtomicLong
方法,去实现一个带有过期时间的自增方法。比较简单,读者自行撸代码吧,这里就不写出了。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  redis
相关文章推荐