springboot如何使用redis的incr创建分布式自增id
作者:有点儿困
这篇文章主要介绍了springboot如何使用redis的incr创建分布式自增id,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
使用redis的incr创建分布式自增id
测试使用springboot加载类测试,使用本地redis, 模拟多线程去生成规律的自增id
@Component public class Common implements CommandLineRunner { @Autowired private RedisTemplate redisTemplate; @Override public void run(String... args) throws Exception { long start = System.currentTimeMillis(); Thread thread1 = new Thread(new Test1()); Thread thread2 = new Thread(new Test1()); Thread thread3 = new Thread(new Test1()); thread1.start(); thread2.start(); thread3.start(); long end = System.currentTimeMillis(); System.out.println("耗时:"+(end-start)); } class Test1 implements Runnable{ @Override public void run() { getId(); } } public void getId(){ synchronized (this) { RedisAtomicLong entityIdCounter = null; for(int i=0;i<10;i++){ if(!redisTemplate.hasKey("ceid")){ redisTemplate.opsForValue().increment("ceid", 1); System.out.println("test1使用redis缓存保存数据成功"); entityIdCounter= new RedisAtomicLong("ceid", redisTemplate.getConnectionFactory()); //incr 默认初始值从0开始, //可以设置初始值, entityIdCounter.set(123); } entityIdCounter=new RedisAtomicLong("ceid", redisTemplate.getConnectionFactory()); long increment=0; increment = entityIdCounter.incrementAndGet(); if (i == 5) { increment = entityIdCounter.decrementAndGet(); System.out.println("test1:失败,返回上个id"); }else{ System.out.println(increment); } } } } }
redis配置在application.properties中
# REDIS # Redis数据库索引(默认为0) spring.redis.database=0 # Redis服务器地址 (默认为127.0.0.1) spring.redis.host=127.0.0.1 # Redis服务器连接端口 (默认为6379) spring.redis.port=6379 # Redis服务器连接密码(默认为空) spring.redis.password= # 连接超时时间(毫秒) spring.redis.timeout=2000ms
springboot redis自增编号控制 踩坑
近段期间,公司 接手一个订单号生成服务,规则的话已经由项目经理他们规定好了,主要是后面的四位数代表的关于当前订单号已经执行第几个了。而这里面有一个要求就是支持分布式。
为了实现这个东西,刚开始我使用了redis的incr来解决这个问题,因为我们后端开发用的是Spring boot,所以我网上找了一个代码如下:
/** * * @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; }
结果测试的时候,看着后面的数很满意,心里面有点小小的激动哦~~
但是当我将数据从小到大排序的时候,发现了一点异样,即刚开始的几个是存在问题的。
所以通过测试发现了,当redis里面还没有设置计时器的一刹那,分布式服务下,会存在前几个重复的现象。
发现这个问题之后,于是我通过redis锁,当判断redis下面还没存在计数key的情况下,锁住,然后在锁住的情况下,其他人进来调用的时候,线程睡眠500ms,然后再往下执行。顺利解决~~~
以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。