<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>

          Redis分布式鎖你會(huì)了嗎?

          共 5816字,需瀏覽 12分鐘

           ·

          2020-09-12 20:26

          點(diǎn)擊上方藍(lán)色字體,選擇“標(biāo)星公眾號(hào)”

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

          66套java從入門到精通實(shí)戰(zhàn)課程分享?

          一、前言

          這里我簡(jiǎn)單說(shuō)一下,代碼可能沒(méi)那么完美。希望各位大佬可以多多指點(diǎn)!!!要是有測(cè)試能力的兄弟可以幫我測(cè)一下,我這個(gè)分段加鎖我是全部都在Redis中實(shí)現(xiàn)主要用到的技術(shù)就是Lua腳本

          二、建議

          建議搭配消息隊(duì)列使用,防止一下進(jìn)來(lái)太多請(qǐng)求。達(dá)到一個(gè)削峰的效果。

          三、簡(jiǎn)述

          嘗試加鎖:首先當(dāng)一個(gè)請(qǐng)求發(fā)送過(guò)來(lái)了,嘗試獲取分段鎖得時(shí)候會(huì)查出所有的分段倉(cāng)庫(kù)的key并嘗試創(chuàng)建標(biāo)識(shí)如果成功返回倉(cāng)庫(kù)的KEY不成功就進(jìn)行下個(gè)倉(cāng)庫(kù)KEY的如果成功了會(huì)使用倉(cāng)庫(kù)的KEY創(chuàng)建一個(gè)標(biāo)識(shí)來(lái)鎖定這個(gè)庫(kù)存并添加過(guò)期時(shí)間然后返回一個(gè) 倉(cāng)庫(kù)的KEY。

          解鎖:根據(jù)之前那個(gè) 倉(cāng)庫(kù)的KEY 查出用戶唯一標(biāo)識(shí)然后和我們解鎖傳入的用戶id進(jìn)行比較看看是否相對(duì)再?zèng)Q定是否釋放這個(gè)鎖,釋放鎖的時(shí)候我們會(huì)檢查庫(kù)存如果為0那么順便刪除庫(kù)存提高下次鎖獲取的效率。


          四、流程圖

          五、核心代碼

          Lua腳本部分為了方便各位大神查看我單獨(dú)寫一個(gè)代碼塊


          //TRY_LOCK
          if?redis.call("EXISTS",KEYS[1])?>?0?then
          ????local?kus?=?redis.call("HKEYS",KEYS[1]);
          ????for?i?=?1,?#kus?do
          ????????if?redis.call('setnx',kus[i],ARGV[1])?>?0?then
          ????????????redis.call('expire',?kus[i],?ARGV[2])
          ????????????return?kus[i];
          ????????end
          ????end
          else
          ????return?nil;
          end

          //DECR
          local?kusName?=?KEYS[1];?local?key?=?KEYS[2];
          local?uid?=??redis.call('get',key);
          local?kuName?=?redis.call('HGET',kusName,key);
          local?kuNum?=?redis.call('get',kuName);
          if?redis.call("EXISTS",kusName)?>?0?then
          ????if?KEYS[3]?==?uid?then
          ????????if?kuNum?~=?nil?and?tonumber(kuNum)?<=?1?then
          ????????????return?redis.call('DECR',kuName);
          ????????else
          ????????????return?null;
          ????????end
          ????end
          else
          ????return?-1;
          end

          //UN_LOCK
          local?kusName?=?KEYS[1];
          local?key?=?KEYS[2];
          local?uid?=??redis.call('get',key);
          local?kuName?=?redis.call('HGET',kusName,key);
          local?kuNum?=?redis.call('get',kuName);
          if?uid?==?KEYS[3]?then
          ????if?kuNum?~=nil?and?tonumber(kuNum)?<=?0?then
          ????????redis.call('hdel',kusName,key);
          ????????redis.call('del',kuName);
          ????end
          ????return?redis.call('del',key);
          end
          return?false;



          package?com.suoxin.core.lock;

          import?com.suoxin.utils.RedisTools;
          import?org.slf4j.Logger;
          import?org.slf4j.LoggerFactory;
          import?javax.annotation.Resource;
          import?java.util.Arrays;
          import?java.util.List;

          /**
          ?*?@author?所心
          ?*?@create?2020-09-01?下午?5:11
          ?*?@description?Redis分段鎖
          ?*/
          public?class?RedisDistributedLock?{

          ????Logger?log?=?LoggerFactory.getLogger(RedisDistributedLock.class);

          ????@Resource
          ????private?RedisTools?tools;
          ?//這里我使用得是lua得方式
          ????private?static?final?String?TRY_LOCK?=?"if?redis.call('EXISTS',KEYS[1])?>?0?then?local?kus?=?redis.call('HKEYS',KEYS[1]);?for?i?=?1,?#kus?do?if?redis.call('setnx',kus[i],ARGV[1])?>?0?then?redis.call('expire',?kus[i],?ARGV[2])?return?kus[i];?end?end?else?return?nil;?end";
          ????private?static?final?String?DECR?=?"local?kusName?=?KEYS[1];?local?key?=?KEYS[2];?local?uid?=??redis.call('get',key);?local?kuName?=?redis.call('HGET',kusName,key);?local?kuNum?=?redis.call('get',kuName);?if?KEYS[3]?==?uid?then?if?kuNum?~=?nil?and?tonumber(kuNum)?>=?1?then?return?redis.call('DECR',kuName);?else?return?nil;?end?end";
          ????private?static?final?String?UN_LOCK?=?"local?kusName?=?KEYS[1];?local?key?=?KEYS[2];?local?uid?=??redis.call('get',key);?local?kuName?=?redis.call('HGET',kusName,key);?local?kuNum?=?redis.call('get',kuName);?if?uid?==?KEYS[3]?then?if?kuNum?~=nil?and?tonumber(kuNum)?<=?0?then?redis.call('hdel',kusName,key);?redis.call('del',kuName);?end?return?redis.call('del',key);?end?return?false;";

          ????private?String?KUS_NAME?=?null;
          ????private?String?UNIQUE_ID?=?null;
          ????private?String?EXPIRE?=?"60";
          ????private?String?KEY_ID?=?null;

          ????/**
          ?????*
          ?????*?@param?KUS_NAME?分段庫(kù)名稱
          ?????*?@param?UNIQUE_ID?唯一標(biāo)識(shí)
          ?????*?@param?EXPIRE?過(guò)期時(shí)間?以秒為單位
          ?????*/
          ????public?RedisDistributedLock(String?KUS_NAME,?String?UNIQUE_ID,?String?EXPIRE)?{
          ????????this.KUS_NAME?=?KUS_NAME;
          ????????this.UNIQUE_ID?=?UNIQUE_ID;
          ????????this.EXPIRE?=?EXPIRE;
          ????????//log.info("參數(shù)初始化:===>總倉(cāng)庫(kù)名稱:?{},?唯一標(biāo)識(shí):?{},?過(guò)期時(shí)間:?{}",KUS_NAME,UNIQUE_ID,EXPIRE);
          ????}

          ????/**
          ?????*??初始化工具類
          ?????*?@param?tools
          ?????*/
          ????public?void?setTools(RedisTools?tools)?{
          ????????this.tools?=?tools;
          ????}

          ????/**
          ?????*?獲取鎖?前面設(shè)置的時(shí)間就是鎖得過(guò)期時(shí)間
          ?????*?@return
          ?????*/
          ????public?boolean?tryLock(){
          ????????List?keys?=?Arrays.asList(KUS_NAME);
          ????????List?args?=?Arrays.asList(UNIQUE_ID,EXPIRE);
          ????????Object?result?=?tools.luaScript(TRY_LOCK,?keys,?args);
          ????????if?(result?!=?null?&&?(result.toString().length()?>?3)){
          ????????????this.KEY_ID?=?result.toString();
          ????????????//log.info("倉(cāng)庫(kù)ID:?{}?返回結(jié)果:?{}?獲取鎖成功",KEY_ID,result);
          ????????????return?true;
          ????????}?else?{
          ????????????//log.info("倉(cāng)庫(kù)ID:?{}?返回結(jié)果:?{}?獲取鎖失敗",KEY_ID,result);
          ????????????return?false;
          ????????}

          ????}

          ????/**
          ?????*?原子性扣減
          ?????*?@return
          ?????*/
          ????public?Integer?decr(){
          ????????Object?result?=?null;
          ????????if?(KEY_ID?!=?null){
          ????????????List?keys?=?Arrays.asList(KUS_NAME,KEY_ID,UNIQUE_ID);
          ????????????List?args?=?Arrays.asList();
          ????????????result?=?tools.luaScript(DECR,keys,args);
          ????????????if?(result?!=?null?&&?!result.toString().isEmpty()){
          ????????????????log.info("消費(fèi)成功?返回結(jié)果:?{}",result);
          ????????????????return?1;
          ????????????}else?{
          ????????????????//log.info("消費(fèi)失敗?返回結(jié)果:?{}",result);
          ????????????????return?0;
          ????????????}
          ????????}
          ????????log.info("已售空...{}"+?result);
          ????????return?-1;
          ????}

          ????/**
          ?????*?釋放鎖
          ?????*/
          ????public?void?unLock(){
          ????????if?(KEY_ID?!=?null){
          ????????????List?keys?=?Arrays.asList(KUS_NAME,KEY_ID,UNIQUE_ID);
          ????????????List?args?=?Arrays.asList();
          ????????????Object?result?=?tools.luaScript(UN_LOCK,?keys,?args);
          ????????????//log.info("釋放鎖?返回結(jié)果:?{}",result);
          ????????}
          ????}
          }



          工具類代碼:

          package?com.suoxin.utils;

          import?org.springframework.data.redis.core.RedisCallback;
          import?org.springframework.data.redis.core.RedisTemplate;
          import?org.springframework.util.CollectionUtils;
          import?redis.clients.jedis.Jedis;
          import?redis.clients.jedis.JedisCluster;

          import?java.util.*;
          import?java.util.concurrent.TimeUnit;

          /**
          ?*?@author?所心
          ?*?@create?2020-08-06?下午?11:01
          ?*?@description?RedisUtils?工具類
          ?*/
          public?class?RedisTools?{

          ????private?RedisTemplate?redisTemplate;

          ????public?void?setRedisTemplate(RedisTemplate?redisTemplate)?{
          ????????this.redisTemplate?=?redisTemplate;
          ????}
          ????
          ????/**
          ?????*?@param?key???鍵
          ?????*?@param?value?值
          ?????*?@return?true成功?false失敗
          ?????*?普通緩存放入
          ?????*/
          ????public?boolean?set(String?key,?Object?value)?{
          ????????try?{
          ????????????redisTemplate.opsForValue().set(key,?value);
          ????????????return?true;
          ????????}?catch?(Exception?e)?{
          ????????????e.printStackTrace();
          ????????????return?false;
          ????????}
          ????}
          ????
          ????/**
          ?????*?@param?key?鍵
          ?????*?@param?map?對(duì)應(yīng)多個(gè)鍵值
          ?????*?@return?true?成功?false?失敗
          ?????*
          ?????*??HashSet
          ?????*/
          ????public?boolean?hmset(String?key,?Map?map)?{
          ????????try?{
          ????????????redisTemplate.opsForHash().putAll(key,?map);
          ????????????return?true;
          ????????}?catch?(Exception?e)?{
          ????????????e.printStackTrace();
          ????????????return?false;
          ????????}
          ????}
          ????????????

          ????public?Map?clear()?{
          ????????Map?map?=?new?HashMap<>();
          ????????try?{
          ????????????//?獲取所有key
          ????????????Set?keys?=?redisTemplate.keys("*");
          ????????????assert?keys?!=?null;
          ????????????//?迭代
          ????????????Iterator?it1?=?keys.iterator();
          ????????????while?(it1.hasNext())?{
          ????????????????//?循環(huán)刪除
          ????????????????redisTemplate.delete(it1.next());
          ????????????}
          ????????????map.put("code",?1);
          ????????????map.put("msg",?"清理全局緩存成功");
          ????????????return?map;
          ????????}?catch?(Exception?e)?{
          ????????????map.put("code",?-1);
          ????????????map.put("msg",?"清理全局緩存失敗");
          ????????????return?map;
          ????????}
          ????}

          ????public?Object?luaScript(String?script,?List?keys,?List?args){
          ????????return?redisTemplate.execute((RedisCallback)?connection?->?{
          ????????????Object?nativeConnection?=?connection.getNativeConnection();
          ????????????//?集群模式
          ????????????if?(nativeConnection?instanceof?JedisCluster)?{
          ????????????????return?((JedisCluster)?nativeConnection).eval(script,?keys,?args);
          ????????????}
          ????????????//?單機(jī)模式
          ????????????else?if?(nativeConnection?instanceof?Jedis)?{
          ????????????????return?((Jedis)?nativeConnection).eval(script,?keys,?args);
          ????????????}
          ????????????return?false;
          ????????});
          ????}
          }



          六、測(cè)試Controller

          package?com.suoxin.controller;

          import?com.suoxin.core.lock.RedisDistributedLock;
          import?com.suoxin.utils.RedisTools;
          import?org.springframework.web.bind.annotation.RequestMapping;
          import?org.springframework.web.bind.annotation.RequestParam;
          import?org.springframework.web.bind.annotation.RestController;

          import?javax.annotation.Resource;
          import?java.util.HashMap;
          import?java.util.Map;
          import?java.util.UUID;
          import?java.util.concurrent.ConcurrentHashMap;

          /**
          ?*?@author?所心
          ?*?@create?2020-09-03?下午?1:22
          ?*?@description?測(cè)試Controller
          ?*/
          @RestController
          public?class?SeckillController?{

          ????@Resource
          ????private?RedisTools?tools;

          ????private?RedisDistributedLock?lock?=?null;
          ?/**
          ?????*
          ?????*?@param?kuname?Redis初始化得Redis庫(kù)名稱
          ?????*?@param?allnum?庫(kù)存總數(shù)
          ?????*?@param?subnum?分段數(shù)
          ?????*?@return?僅是測(cè)試沒(méi)有寫太完美但是核心代碼還是五臟俱全得
          ?????*/
          ????@RequestMapping("/init")
          ????public?Map?init(@RequestParam("kuname")?String?kuname,@RequestParam("allnum")?Integer?allnum,@RequestParam("subnum")?Integer?subnum){

          ????????ConcurrentHashMap?map?=?new?ConcurrentHashMap();
          ????????int?max=100000,min=1000;
          ????????for?(int?i?=?0;?i?
          ????????????long?nowtime?=?System.currentTimeMillis();
          ????????????int?ran2?=?(int)?(Math.random()*(max-min)+min);

          ????????????map.put(UUID.randomUUID().toString(),?Long.parseLong(nowtime+""+ran2));
          ????????????tools.set(nowtime+""+ran2,?subnum);
          ????????}
          ????????tools.hmset(kuname,?map);

          ????????Map?map1?=?new?HashMap<>();
          ????????map1.put("msg","成功");
          ????????return?map1;
          ????}
          ?/**
          ?????*
          ?????*?@param?kuname?初始化時(shí)得Redis倉(cāng)庫(kù)名稱
          ?????*?@param?timeout?超時(shí)時(shí)間
          ?????*?@return
          ?????*/
          ????@RequestMapping("/seckill")
          ????public?Map?seckill(@RequestParam("kuname")?String?kuname,@RequestParam(value?=?"timeout",defaultValue?=?"5")?String?timeout){
          ????????Map?map1?=?new?HashMap<>();
          ????????long?run?=?System.currentTimeMillis();
          ????????//初始化鎖
          ????????lock?=?new?RedisDistributedLock(kuname,?UUID.randomUUID().toString(),?timeout);
          ????????lock.setTools(tools);
          ????????try?{
          ????????????//獲取鎖
          ????????????if?(lock.tryLock())?{
          ????????????????map1.put("msg","恭喜您搶到了!!!:"?+?lock.decr());
          ????????????}?else?{
          ????????????????map1.put("msg","很遺憾您沒(méi)有搶到?╥﹏╥...");
          ????????????}
          ????????}?finally?{
          ????????????//計(jì)算時(shí)間
          ????????????long?end??=?System.currentTimeMillis();
          ????????????map1.put("elapsedTime","耗時(shí):===>"+?(end-run)?+"ms");
          ????????????//釋放鎖
          ????????????lock.unLock();
          ????????????return?map1;
          ????????}
          ????}
          }





          版權(quán)聲明:本文為博主原創(chuàng)文章,遵循?CC 4.0 BY-SA?版權(quán)協(xié)議,轉(zhuǎn)載請(qǐng)附上原文出處鏈接和本聲明。

          本文鏈接:

          http://blog.csdn.net/G3187576034/article/details/108482317



          粉絲福利:108本java從入門到大神精選電子書領(lǐng)取

          ???

          ?長(zhǎng)按上方鋒哥微信二維碼?2 秒
          備注「1234」即可獲取資料以及
          可以進(jìn)入java1234官方微信群



          感謝點(diǎn)贊支持下哈?

          瀏覽 34
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <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>
                    在线观看免费成人网站 | 国产夜间福利视频 | igao视频在线观看 | 久久三级片成年人 | 干少妇电影无码 |