<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          redisTemplate分布式鎖演變,redission分布式鎖實現(xiàn)!

          共 13426字,需瀏覽 27分鐘

           ·

          2021-08-01 16:26

          點擊上方藍色字體,選擇“標星公眾號”

          優(yōu)質(zhì)文章,第一時間送達

          基本原理

          我們可以同時去一個地方“占坑”,如果占到,就執(zhí)行邏輯。否則就必須等待,直到釋放鎖?!罢伎印笨梢匀edis,可以去數(shù)據(jù)庫,可以去任何大家都能訪問的地方。等待可以自旋的方式。

          階段一

          public Map<String, List<Catalog2Vo>> getCatalogJsonDbWithRedisLock() {
                  //階段一
                  Boolean lock = stringRedisTemplate.opsForValue().setIfAbsent("lock""111");
                  //獲取到鎖,執(zhí)行業(yè)務
                  if (lock) {
                      Map<String, List<Catalog2Vo>> categoriesDb = getCategoryMap();
                      //刪除鎖,如果在此之前報錯或宕機會造成死鎖
                      stringRedisTemplate.delete("lock");
                      return categoriesDb;
                  }else {
                      //沒獲取到鎖,等待100ms重試
                      try {
                          Thread.sleep(100);
                      } catch (InterruptedException e) {
                          e.printStackTrace();
                      }
                      return getCatalogJsonDbWithRedisLock();
                  }
              }
           
          public Map<String, List<Catalog2Vo>> getCategoryMap() {
                  ValueOperations<String, String> ops = stringRedisTemplate.opsForValue();
                  String catalogJson = ops.get("catalogJson");
                  if (StringUtils.isEmpty(catalogJson)) {
                      System.out.println("緩存不命中,準備查詢數(shù)據(jù)庫。。。");
                      Map<String, List<Catalog2Vo>> categoriesDb= getCategoriesDb();
                      String toJSONString = JSON.toJSONString(categoriesDb);
                      ops.set("catalogJson", toJSONString);
                      return categoriesDb;
                  }
                  System.out.println("緩存命中。。。。");
                  Map<String, List<Catalog2Vo>> listMap = JSON.parseObject(catalogJson, new TypeReference<Map<String, List<Catalog2Vo>>>() {});
                  return listMap;
              }

           問題:1、setnx占好了位,業(yè)務代碼異常或者程序在頁面過程中宕機。沒有執(zhí)行刪除鎖邏輯,這就造成了死鎖

          解決:設置鎖的自動過期,即使沒有刪除,會自動刪除

          階段二

           public Map<String, List<Catalog2Vo>> getCatalogJsonDbWithRedisLock() {
                  Boolean lock = stringRedisTemplate.opsForValue().setIfAbsent("lock""111");
                  if (lock) {
                      //設置過期時間
                      stringRedisTemplate.expire("lock", 30, TimeUnit.SECONDS);
                      Map<String, List<Catalog2Vo>> categoriesDb = getCategoryMap();
                      stringRedisTemplate.delete("lock");
                      return categoriesDb;
                  }else {
                      try {
                          Thread.sleep(100);
                      } catch (InterruptedException e) {
                          e.printStackTrace();
                      }
                      return getCatalogJsonDbWithRedisLock();
                  }
              }

          問題:1、setnx設置好,正要去設置過期時間,宕機。又死鎖了。解決:設置過期時間和占位必須是原子的。redis支持使用setnx ex命令

          階段三

          public Map<String, List<Catalog2Vo>> getCatalogJsonDbWithRedisLock() {
              //加鎖的同時設置過期時間,二者是原子性操作
              Boolean lock = stringRedisTemplate.opsForValue().setIfAbsent("lock""1111",5, TimeUnit.SECONDS);
              if (lock) {
                  Map<String, List<Catalog2Vo>> categoriesDb = getCategoryMap();
                  //模擬超長的業(yè)務執(zhí)行時間
                  try {
                      Thread.sleep(6000);
                  } catch (InterruptedException e) {
                      e.printStackTrace();
                  }
                  stringRedisTemplate.delete("lock");
                  return categoriesDb;
              }else {
                  try {
                      Thread.sleep(100);
                  } catch (InterruptedException e) {
                      e.printStackTrace();
                  }
                  return getCatalogJsonDbWithRedisLock();
              }
          }

           問題:1、刪除鎖直接刪除???如果由于業(yè)務時間很長,鎖自己過期了,我們直接刪除,有可能把別人正在持有的鎖刪除了。解決:占鎖的時候,值指定為uuid,每個人匹配是自己的鎖才刪除。

          階段四

          public Map<String, List<Catalog2Vo>> getCatalogJsonDbWithRedisLock() {
                  String uuid = UUID.randomUUID().toString();
                  ValueOperations<String, String> ops = stringRedisTemplate.opsForValue();
                //為當前鎖設置唯一的uuid,只有當uuid相同時才會進行刪除鎖的操作
                  Boolean lock = ops.setIfAbsent("lock", uuid,5, TimeUnit.SECONDS);
                  if (lock) {
                      Map<String, List<Catalog2Vo>> categoriesDb = getCategoryMap();
                      String lockValue = ops.get("lock");
                      if (lockValue.equals(uuid)) {
                          try {
                              Thread.sleep(6000);
                          } catch (InterruptedException e) {
                              e.printStackTrace();
                          }
                          stringRedisTemplate.delete("lock");
                      }
                      return categoriesDb;
                  }else {
                      try {
                          Thread.sleep(100);
                      } catch (InterruptedException e) {
                          e.printStackTrace();
                      }
                      return getCatalogJsonDbWithRedisLock();
                  }
              }

          問題:1、如果正好判斷是當前值,正要刪除鎖的時候,鎖已經(jīng)過期,別人已經(jīng)設置到了新的值。那么我們刪除的是別人的鎖解決:刪除鎖必須保證原子性。使用redis+Lua腳本完成

          階段五-最終形態(tài)

           public Map<String, List<Catalog2Vo>> getCatalogJsonDbWithRedisLock() {
                  String uuid = UUID.randomUUID().toString();
                  ValueOperations<String, String> ops = stringRedisTemplate.opsForValue();
                  Boolean lock = ops.setIfAbsent("lock", uuid,5, TimeUnit.SECONDS);
                  if (lock) {
                      Map<String, List<Catalog2Vo>> categoriesDb = getCategoryMap();
                      String lockValue = ops.get("lock");
                      String script = "if redis.call(\"get\",KEYS[1]) == ARGV[1] then\n" +
                              "    return redis.call(\"del\",KEYS[1])\n" +
                              "else\n" +
                              "    return 0\n" +
                              "end";
                      stringRedisTemplate.execute(new DefaultRedisScript<Long>(script, Long.class), Arrays.asList("lock"), lockValue);
                      return categoriesDb;
                  }else {
                      try {
                          Thread.sleep(100);
                      } catch (InterruptedException e) {
                          e.printStackTrace();
                      }
                      return getCatalogJsonDbWithRedisLock();
                  }
              }

          保證加鎖【占位+過期時間】和刪除鎖【判斷+刪除】的原子性。更難的事情,鎖的自動續(xù)期

          4) Redisson

          Redisson是一個在Redis的基礎上實現(xiàn)的Java駐內(nèi)存數(shù)據(jù)網(wǎng)格(In-Memory Data Grid)。它不僅提供了一系列的分布式的Java常用對象,還提供了許多分布式服務。其中包括(BitSetSetMultimapSortedSetMapListQueueBlockingQueueDequeBlockingDequeSemaphoreLockAtomicLongCountDownLatchPublish / SubscribeBloom filterRemote serviceSpring cacheExecutor serviceLive Object serviceScheduler service) Redisson提供了使用Redis的最簡單和最便捷的方法。Redisson的宗旨是促進使用者對Redis的關注分離(Separation of Concern),從而讓使用者能夠?qū)⒕Ω械胤旁谔幚順I(yè)務邏輯上。


            作者 |  zhangkaixuan456

          來源 |  csdn.net/zhangkaixuan456/article/details/110679617


          瀏覽 89
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  国产爆操| 激情五月成人网 | 亚洲无 码A片 | 中文字幕欧美日韩VA免费视频 | 国内免费精品视频 |