分布式鎖,其實原理是就是多臺機(jī)器,去爭搶一個資源,誰爭搶成功,那么誰就持有了這把鎖,然后去執(zhí)行后續(xù)的業(yè)務(wù)邏輯,執(zhí)行完畢后,把鎖釋放掉。
可以通過多種途徑實現(xiàn)分布式鎖,例如利用數(shù)據(jù)庫(mysql等),插入一條記錄(唯一索引),誰插入成功,誰就持有鎖;還可通過zookeeper來實現(xiàn)分布式鎖,誰創(chuàng)建節(jié)點成功,誰就持有鎖。本文介紹通過redis來實現(xiàn)分布式鎖。
本文使用springboot提供的RedisTemplate來操作redis,可以參考我之前的文章【快學(xué)springboot】13.操作redis之String數(shù)據(jù)結(jié)構(gòu),這里對使用RedisTemplate來操作redis做了介紹。當(dāng)然也可以直接使用jedis來操作redis,大家可以參考下jedis的文檔,使用上都是大同小異的。
實現(xiàn)分布式鎖的步驟
第一步:通過redis的setnx方式(不存在則設(shè)置),往redis上設(shè)置一個帶有過期時間的key,如果設(shè)置成功,則獲得了分布式鎖。這里設(shè)置過期時間,是防止在釋放鎖的時候出現(xiàn)異常導(dǎo)致鎖釋放不掉。
第二步:執(zhí)行完業(yè)務(wù)操作之后,刪除該鎖。
實現(xiàn)
新建一個DistributedLock.class,注入StringRedisTemplate。
@ComponentpublicclassDistributedLock{@AutowiredprivateStringRedisTemplate redisTemplate;}
獲得鎖
/**
* 獲得鎖
*/publicbooleangetLock(StringlockId, long millisecond){Booleansuccess = redisTemplate.opsForValue().setIfAbsent(lockId,"lock", millisecond, TimeUnit.MILLISECONDS);returnsuccess !=null&& success; }
setIfAbsent方法,就是當(dāng)鍵不存在的時候,設(shè)置,并且該方法可以設(shè)置鍵的過期時間。該方法對應(yīng)到redis的原生命令就是:
SETlockIdcontentPX millisecond NX
至于設(shè)置多少的過期時間合適,這個是沒有定論的,需要根據(jù)真是的業(yè)務(wù)場景來衡量。
釋放鎖
當(dāng)處理完業(yè)務(wù)邏輯后,需要手動的把鎖釋放掉。
publicvoidreleaseLock(StringlockId){ redisTemplate.delete(lockId); }
釋放鎖的操作比較簡單,直接刪除之前設(shè)置的鍵即可。其實,基于redis實現(xiàn)分布式鎖的方式,在釋放鎖的時候,是存在釋放失敗的風(fēng)險的(比如網(wǎng)路抖動什么的),這也是為什么在設(shè)置鎖的時候需要設(shè)置過期時間的原因,可以防止在出現(xiàn)異常的時候,鎖會自動的消失掉。同時,我們也可以增加幾次失敗之后的重試機(jī)制。
本人親測可用,很簡潔。
原文地址?https://www.cnblogs.com/happy4java/p/11205993.html