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,然後再往下執行。順利解決~~~

以上為個人經驗,希望能給大傢一個參考,也希望大傢多多支持WalkonNet。

推薦閱讀: