分布式鎖(1) ----- 介紹和基於數據庫的分布式鎖
線程鎖與分布式鎖
1.java的synchronize和Lock都是屬於線程鎖,只能保證同一個進程內的多線程對共享變量修改訪問同步。它們的原理都是設置一個可以讓所有線程訪問到標記,如synchronize是設置對象頭的Mark Word,而Lock類是基於AQS的volatile修飾的state。
2.分布式鎖是屬於進程範疇的,而且進程可以在不同的機器上。它要保證的是多個進程對共享變量修改訪問同步(例如集群環境下同時修改緩存和數據庫)。分布式鎖也同樣需要一個可以讓所有進程訪問到的標記(如數據庫的字段,redis的數據,zookeeper的節點等)來控制同步。
實現方法
1.基於數據庫的分布式鎖
2.基於redis的分布式鎖
3.基於zookeeper的分布式鎖
基於數據庫的分布式鎖
基於表主鍵唯一
利用主鍵具有唯一性的性質,加鎖時向數據庫插入以鎖名為主鍵的數據,解鎖時刪除該數據。
優化:
1.沒有過期時間,如果獲得鎖的服務解鎖失敗,將導致其他服務無法獲得鎖。網上也有解決方法:增加過期時間字段,定期清除過期鎖數據。
2.重入性,增加獲得鎖服務的標記字段。
基於版本號字段
為表結構增加版本號字段,每次獲取數據將版本號獲取到,下次修改數據時判斷當前版本是否該版本號。思路是與mysql的mvcc機制差不多的。
基於排他鎖
public boolean lock(){ connection.setAutoCommit(false) while(true){ try{ result = select * from lock where lockName=xxx for update; if(result==null){ return true; } }catch(Exception e){ } sleep(1000); } return false; } public void unlock(){ connection.commit(); }
1.該方法是基於mysql的innodb的行級鎖,所以lockName字段必須有索引存在,但因此也有一個問題,是否使用索引是有mysql來判斷的,如果mysql認為全表查詢更快,會使用表鎖,那將會影響lock表的所有分布式鎖。
2.for update會在執行失敗是一直阻塞到成功。
優缺點
優點:容易實現理解
缺點:占用數據庫連接,性能較低。
參考資料
https://www.cnblogs.com/seesun2012/p/9214653.html
分布式鎖(1) ----- 介紹和基於數據庫的分布式鎖