Redission分布式鎖踩坑

踩坑1:數據庫事務超時

先了解一下“鎖互斥機制”

比如客戶端1拿到鎖之后,還未執行完代碼,此時客戶端2來嘗試拿鎖,

第一個判斷:客戶端2這時候會發現這個鎖已經存在了

第二個判斷:是否是客戶端2加的鎖,但是也發現不是,因為是客戶端1加的鎖

然后客戶端2會獲取到這個鎖的剩余生存時間,此時客戶端2會進入一個while循環,不停的嘗試加鎖。

偽代碼:

@Transaction

???public void lock() {

????????while (true) {

????????????boolean flag = this.getLock(key);

????????????if (flag) {

????????????????insert();

????????????}

????????}

????}

這里有個@Transaction事務注解,比如

boolean flag = this.getLock(key);

這塊代碼遲遲拿不到鎖,超過了事務的時間限制,程序就會報數據庫事務超時的異常;或者我們在執行insert();這塊代碼時,執行時間太長可能也會超過事務的時間限制,從而也導致程序報數據庫超時的異常。一般解決這種問題就要:將數據庫事務改為手動提交、回滾事務。

@Autowired

????DataSourceTransactionManager dataSourceTransactionManager;


????@Transaction

????public void lock() {

//手動開啟事務

????????TransactionStatus transactionStatus = dataSourceTransactionManager.getTransaction(transactionDefinition);

????????try {

????????????while (true) {

????????????????boolean flag = this.getLock(key);

????????????????if (flag) {

????????????????????insert();

//手動提交事務

????????????????????dataSourceTransactionManager.commit(transactionStatus);

????????????????}

????????????}

????????} catch (Exception e) {

//手動回滾事務

????????????dataSourceTransactionManager.rollback(transactionStatus);

????????}

????}


踩坑2:redis的鎖未被釋放,連接池爆滿

這種情況是一種低級錯誤,由于當前線程獲取到redis鎖,處理完業務后未及時釋放鎖,導致其它線程會一直嘗試獲取鎖阻塞,例如:用Jedis客戶端會報如下的錯誤信息

redis.clients.jedis.exceptions.JedisConnectionException: Could not get a resource from the pool

redis線程池已經沒有空閑線程來處理客戶端命令。


解決辦法


void update(){

????do{

????????redis=JedisUtil.getJedis();

????????flag = getLock(key,redis);

????????if(flag){

????????????update();

????????}else{

//釋放當前redis連接

//由于我們的業務場景屬于比較耗時的業務型,所以在這里休眠1000毫秒

????????????redis.close();

????????????sleep(1000);

????????}

????}while(true)

}

1.當前請求獲取鎖,如果獲取不到,則釋放當前連接,并休眠一會;

2.合理配置redis連接池大小,主要參考具體業務場景的并發量來設置;

3.如果是重入鎖未拿到鎖后,線程可以釋放當前連接并且sleep一段時間。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。