欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Spring?Boot?集成Redisson實(shí)現(xiàn)分布式鎖詳細(xì)案例

 更新時(shí)間:2022年08月05日 08:17:42   作者:劍圣無痕???????  
這篇文章主要介紹了Spring?Boot?集成Redisson實(shí)現(xiàn)分布式鎖詳細(xì)案例,文章圍繞主題展開詳細(xì)的內(nèi)容介紹,具有一定的參考價(jià)值,需要的朋友可以參考一下

前言

Spring Boot集成Redis實(shí)現(xiàn)單機(jī)分布式鎖針對單機(jī)分布式鎖還是存在鎖定續(xù)期、可重入的問題,本文將采用Spring Boot 集成Ression實(shí)現(xiàn)分布式鎖進(jìn)行詳細(xì)講解。

分布式鎖實(shí)現(xiàn)

引入jar包

  <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
    <exclusions>
      <exclusion>
         <groupId>io.lettuce</groupId>
         <artifactId>lettuce-core</artifactId>
      </exclusion>  
    </exclusions>
   </dependency>
	  
      <dependency>
         <groupId>org.redisson</groupId>
         <artifactId>redisson-spring-boot-starter</artifactId>
         <version>3.13.6</version>
     </dependency>

說明:關(guān)于集成Redisson,我們需要注意與Spring Boot的版本對應(yīng)。

具體對應(yīng)的關(guān)系如下:

注意:3.13.6對應(yīng)的Spring Boot的版本為2.3.0,而redis-spring-data為redis-spring-data-23。我們可以通過查看pom文件的引用從而得到依賴關(guān)系。

Redisson的配置

application.yml中引入redisson.yml配置

  redis:
    redisson:
      file: classpath:redisson.yml

redisson.yml配置

singleServerConfig:
  password: xxxx
  address: "redis://127.0.0.1:6379"
  database: 1
threads: 0
nettyThreads: 0
codec: !<org.redisson.codec.FstCodec> {}
transportMode: "NIO"

說明:本文配置的是單機(jī)環(huán)境,如果需要配置集群環(huán)境,可以采用如下配置:

 clusterServersConfig:
          idleConnectionTimeout: 10000
          connectTimeout: 10000
          timeout: 3000
          retryAttempts: 3
          retryInterval: 1500
          failedSlaveReconnectionInterval: 3000
          failedSlaveCheckInterval: 60000
          password: null
          subscriptionsPerConnection: 5
          clientName: null
          loadBalancer: !<org.redisson.connection.balancer.RoundRobinLoadBalancer> {}
          subscriptionConnectionMinimumIdleSize: 1
          subscriptionConnectionPoolSize: 50
          slaveConnectionMinimumIdleSize: 24
          slaveConnectionPoolSize: 64
          masterConnectionMinimumIdleSize: 24
          masterConnectionPoolSize: 64
          readMode: "SLAVE"
          subscriptionMode: "SLAVE"
          nodeAddresses:
          - "redis://127.0.0.1:7004"
          - "redis://127.0.0.1:7001"
          - "redis://127.0.0.1:7000"
          scanInterval: 1000
          pingConnectionInterval: 0
          keepAlive: false
          tcpNoDelay: false
        threads: 16
        nettyThreads: 32
        codec: !<org.redisson.codec.MarshallingCodec> {}
        transportMode: "NIO"

封裝Redisson工具類

@Component
public class RedissonLockUtil
{
    private static final Logger logger = LoggerFactory.getLogger(RedissonLockUtil.class);
    
        @Autowired
        private RedissonClient redissonClient;
     
        /**
         * 加鎖
         * @param lockKey
         * @return
         */
        public RLock lock(String lockKey) 
        {
            RLock lock = redissonClient.getLock(lockKey);
            return lock;
        }
     
        /**
         * 公平鎖
         * @param key
         * @return
         */
        public RLock fairLock(String key) 
        {
            return redissonClient.getFairLock(key);
        }
        
        /**
         * 帶超時(shí)的鎖
         * @param lockKey
         * @param timeout 超時(shí)時(shí)間 單位:秒
         */
        public RLock lock(String lockKey, int timeout) 
        {
            RLock lock = redissonClient.getLock(lockKey);
            lock.lock(timeout, TimeUnit.SECONDS);
            return lock;
        }

        /**
         * 讀寫鎖
         * @param key
         * @return
         */
        public RReadWriteLock readWriteLock(String key) {
            return redissonClient.getReadWriteLock(key);
        }

        /**
         * 帶超時(shí)的鎖
         * @param lockKey
         * @param unit 時(shí)間單位
         * @param timeout 超時(shí)時(shí)間
         */
        public RLock lock(String lockKey, TimeUnit unit ,int timeout) {
            RLock lock = redissonClient.getLock(lockKey);
            lock.lock(timeout, unit);
            return lock;
        }

        /**
         * 加鎖
         * @param key
         * @param supplier
         * @return
         */
        public <T> T lock(String key, Supplier<T> supplier) {
            RLock lock = lock(key);
            try {
                lock.lock();
                return supplier.get();
            } finally {
                if (lock != null && lock.isLocked()) {
                    lock.unlock();
                }
            }
        }


        /**
         * 嘗試獲取鎖
         * @param lockKey
         * @param waitTime 等待時(shí)間
         * @param leaseTime 自動釋放鎖時(shí)間
         * @return
         */
        public  boolean tryLock(String lockKey, int waitTime, int leaseTime) {
            RLock lock = redissonClient.getLock(lockKey);
            try {
                return lock.tryLock(waitTime, leaseTime, TimeUnit.SECONDS);
            } catch (InterruptedException e) {
                return false;
            }
        }

        /**
         * 嘗試獲取鎖
         * @param lockKey
         * @param unit 時(shí)間單位
         * @param waitTime 等待時(shí)間
         * @param leaseTime 自動釋放鎖時(shí)間
         * @return
         */
        public boolean tryLock(String lockKey, TimeUnit unit, int waitTime, int leaseTime) {
            RLock lock = redissonClient.getLock(lockKey);
            try {
                return lock.tryLock(waitTime, leaseTime, unit);
            } catch (InterruptedException e) {
                return false;
            }
        }

        /**
         * 釋放鎖
         * @param lockKey
         */
        public void unlock(String lockKey) {
            RLock lock = redissonClient.getLock(lockKey);
            lock.unlock();
        }


        /**
         * 釋放鎖
         * @param lock
         */
        public void unlock(RLock lock) 
        {
            lock.unlock();
        }
    }  

模擬秒殺扣減庫存

 public int lockStock()
    {
        String lockKey="lock:stock";
        String clientId = UUID.randomUUID().toString();

        //加鎖
        RLock lock=redissonLockUtil.lock(lockKey);
        lock.lock();

        try
        {
           logger.info("加鎖成功 clientId:{}",clientId);
           int stockNum= Integer.valueOf((String)redisUtil.get("seckill:goods:stock"));
           if(stockNum>0)
           {
              stockNum--;
              redisUtil.set("seckill:goods:stock",String.valueOf(stockNum));
              logger.info("秒殺成功,剩余庫存:{}",stockNum);
           }
           else
           {
              logger.error("秒殺失敗,剩余庫存:{}", stockNum);
           }
           //獲取庫存數(shù)量
           return stockNum;
        }
        catch (Exception e)
        {
           logger.error("decry stock eror",e);
        }
        finally
        {
            if(lock!=null)
            {
                lock.unlock(); 
            }
        }
        return 0;
    }

測試代碼

@RequestMapping("/redisLockTest")
    public void redisLockTest()
    {
        // 初始化秒殺庫存數(shù)量
        redisUtil.set("seckill:goods:stock", "10");

        List<Future> futureList = new ArrayList<>();

        //多線程異步執(zhí)行
        ExecutorService executors = Executors.newScheduledThreadPool(10);
        //
        for (int i = 0; i < 30; i++)
        {
            futureList.add(executors.submit(this::lockStock));

            try
            {
               Thread.sleep(100);
            }
            catch (InterruptedException e) 
            {
               logger.error("redisLockTest error",e);
            }
        }

        // 等待結(jié)果,防止主線程退出
        futureList.forEach(t -> {
            try 
            {
                int stockNum =(int) t.get();
                logger.info("庫存剩余數(shù)量:{}",stockNum);
            }
            catch (Exception e)
            {
               logger.error("get stock num error",e);
            }
        });
    }

執(zhí)行結(jié)果如下:

總結(jié)

本文針對Spring Boot集成Redisson的基本使用,關(guān)于Redisson源碼的分析將在后續(xù)的文章中進(jìn)行講解,如有疑問,請隨時(shí)反饋,

相關(guān)文章

  • 全面解析Java中的GC與幽靈引用

    全面解析Java中的GC與幽靈引用

    一般的應(yīng)用程序不會涉及到 Reference 編程, 但是了解這些知識會對理解 GC 的工作原理以及性能調(diào)優(yōu)有一定幫助,在實(shí)現(xiàn)一些基礎(chǔ)性設(shè)施比如緩存時(shí)也可能會用到,希望本文能有所幫助
    2013-09-09
  • Java中的Vector詳細(xì)解讀

    Java中的Vector詳細(xì)解讀

    這篇文章主要介紹了Java中的Vector詳細(xì)解讀,Vector是實(shí)現(xiàn)了List接口的子類,其底層是一個(gè)對象數(shù)組,維護(hù)了一個(gè)elementData數(shù)組,是線程安全的,Vector類的方法帶有synchronized關(guān)鍵字,在開發(fā)中考慮線程安全中使用Vector,需要的朋友可以參考下
    2023-09-09
  • JEE與Spring Boot代碼性能比較分析

    JEE與Spring Boot代碼性能比較分析

    JavaEE與Spring Boot其實(shí)很難比較測試,前者適合單體SOA架構(gòu),后者適合微服務(wù),但是還是有好事者把兩者放在一起比較性能。這篇文章主要介紹了JEE與Spring Boot代碼性能比較,需要的朋友可以參考下
    2018-11-11
  • 如何使用try-with-resource機(jī)制關(guān)閉連接

    如何使用try-with-resource機(jī)制關(guān)閉連接

    這篇文章主要介紹了使用try-with-resource機(jī)制關(guān)閉連接的操作,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-07-07
  • java程序員必須知道的4個(gè)書寫代碼技巧

    java程序員必須知道的4個(gè)書寫代碼技巧

    本篇文章主要給大家講述了作為JAVA程序員如何能寫出高效的代碼以及運(yùn)行效率更高的代碼,一起學(xué)習(xí)分享下吧。
    2017-12-12
  • Java虛擬機(jī)JVM之server模式與client模式的區(qū)別

    Java虛擬機(jī)JVM之server模式與client模式的區(qū)別

    這篇文章主要介紹了Java虛擬機(jī)JVM的client模式和Server模式兩者的區(qū)別和聯(lián)系
    2017-12-12
  • Java中序列化與反序列化的特性解讀

    Java中序列化與反序列化的特性解讀

    這篇文章主要介紹了Java中序列化與反序列化的特性解讀,當(dāng)我們需要將內(nèi)存中的對象持久化到磁盤,數(shù)據(jù)庫中時(shí), 當(dāng)我們需要與瀏覽器進(jìn)行交互時(shí),當(dāng)我們需要實(shí)現(xiàn) RPC 時(shí), 這個(gè)時(shí)候就需要序列化和反序列化了,需要的朋友可以參考下
    2023-08-08
  • Spring?boot2.0?實(shí)現(xiàn)日志集成的方法(2)

    Spring?boot2.0?實(shí)現(xiàn)日志集成的方法(2)

    這篇文章主要介紹了Spring?boot2.0?實(shí)現(xiàn)日志集成的方法,上一章講解了spring?boot日志簡單集成,這篇我們將日志進(jìn)行分類,常規(guī)日志、異常日志、監(jiān)控日志等,需要將日志輸出到不同的文件,具體內(nèi)容需要的小伙伴可以參考一下
    2022-04-04
  • Java工廠模式的使用細(xì)則介紹

    Java工廠模式的使用細(xì)則介紹

    工廠模式,是一種實(shí)例化對象的方式,只要輸入需要實(shí)例化對象的名字,就可以通過工廠對象的相應(yīng)工廠函數(shù)來制造你需要的對象
    2023-02-02
  • SpringBoot利用jpa連接MySQL數(shù)據(jù)庫的方法

    SpringBoot利用jpa連接MySQL數(shù)據(jù)庫的方法

    這篇文章主要介紹了SpringBoot利用jpa連接MySQL數(shù)據(jù)庫的方法,本文通過示例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2022-10-10

最新評論