日韩av黄I国产麻豆传媒I国产91av视频在线观看I日韩一区二区三区在线看I美女国产在线I麻豆视频国产在线观看I成人黄色短片

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 >

接口幂等性的设计之————redis分布式锁的应用

發布時間:2024/9/30 34 豆豆
生活随笔 收集整理的這篇文章主要介紹了 接口幂等性的设计之————redis分布式锁的应用 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

接口冪等性的設計之————redis分布式鎖的應用

在集群分布式機器部署的前提下,接口在相同數據高并發的情況下如果沒有唯一索引的情況下,可能會有一些問題。

比如:

插入或更新商品的接口,如果沒有則插入,有則更新的接口。支持多次修改。

考慮一種情況,前端頁面第一次提交時瞬間點擊多次。這種情況下會先去數據庫查詢,然后再插入。(當然唯一索引也可以解決,但是這種的有一次提交將會被拒絕)。

所有分布式鎖的使用場景可以類比于以前使用sychronized的場景,java自己的鎖只適用于單jvm的場景,在多jvm的時候只能用分布式鎖來解決。

下面看下簡單的使用

/*** * @param lockName 鎖名稱* @param acquireTimeout 等待獲取鎖時間* @param lockTimeout 鎖超時時間* @return*/ public String acquireRedisLock(String lockName, long acquireTimeout, long lockTimeout) {Jedis jedis = getRedisResource();if (jedis == null) {logger.error("get resource failed");return null;}String identifier = UUID.randomUUID().toString();String lockKey =lockName;int lockExpire = (int)(lockTimeout / 1000);try {long end = System.currentTimeMillis() + acquireTimeout;while (System.currentTimeMillis() < end) {if (jedis.setnx(lockKey, identifier) == 1){jedis.expire(lockKey, lockExpire);return identifier;}if (jedis.ttl(lockKey) == -1) {jedis.expire(lockKey, lockExpire);}try {Thread.sleep(1);}catch(InterruptedException ie){Thread.currentThread().interrupt();}}} catch (Exception e) {logger.error("acquireLockWithFullLockKey 獲取分布式鎖出現問題,",e);} finally {jedis.close();}// null indicates that the lock was not acquiredreturn null; }/*** 釋放分布式鎖* @param lockName* @param identifier* @return*/ public boolean releaseLock(String lockName, String identifier) {Jedis jedis = getRedisResource();String lockKey = lockName;try {while (true){jedis.watch(lockKey);if (identifier.equals(jedis.get(lockKey))){Transaction trans = jedis.multi();trans.del(lockKey);List<Object> results = trans.exec();if (results == null){continue;}return true;}jedis.unwatch();break;}} catch (Exception e) {logger.error("releaseLock 釋放分布式鎖出現問題,",e);} finally {jedis.close();}return false; }

釋放的時候用到了redis的watch命令和multi,exec,主要是事務方面操作,防止被key的值修改后刪除。和jedis.get出來的值不一樣。

redis的操作可以見我博客后續關于redis的文章。

這兩個方法有了之后,一個redis分布式鎖就好了,來看看使用:

public void runAmethod() {String lockId = lock.acquireLock("get", 2000, 5000);boolean isLock = StringUtils.isNotBlank(lockId);if (isLock) {System.out.println("執行方法============");} else {logger.error("未獲取到redis鎖,不能執行");}if (null != lockId) {lock.releaseLock("get", lockId);} }

使用時直接這樣,鎖名字每個方法應該不同,鎖獲取時間根據方法一般執行時間設置,超時時間應該要考慮到吞吐量和接口的最長執行時間。太長了吞吐量不夠,太短了可能會導致并發問題。

后續,如果要進一步封裝可以這樣:

首先定義一個接口

package com.service;public interface RedisLockMethod {void runMethod();}

然后使用:

先看無鎖情況下:

public void test() {noLockMethod(); }private void noLockMethod() {System.out.println("我是之前無鎖的方法"); }

test方法里面的方法現在要加分布式鎖處理,該怎么操作呢?

public void test() {//1,lamda寫法runAmethod(()->noLockMethod());//2,匿名內部類寫法runAmethod(new RedisLockMethod() {@Overridepublic void runMethod() {//原有的方法noLockMethod();}});} private void noLockMethod() {System.out.println("我是之前無鎖的方法"); }public void runAmethod(RedisLockMethod aaa){String lockId = lock.acquireLock("get", 2000, 5000);boolean isLock = StringUtils.isNotBlank(lockId);if (isLock) {aaa.runMethod();} else {logger.error("未獲取到redis鎖,不能執行");}if (null != lockId) {lock.releaseLock("get", lockId);} }

提供了兩種方法,比較推薦lamda寫法。這種寫法下runAmethod()這個方法可以抽取出來作為公共的方法,所有需要分布式鎖的時候直接調用即可,里面封裝要鎖的方法即可。

總結

以上是生活随笔為你收集整理的接口幂等性的设计之————redis分布式锁的应用的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。