分佈式鎖產生的緣由是:當多個客戶端要同時併發操做數據庫時,可能查出來的數據是相同的然後繼續寫的時候會出現事務方面的問題。如:商品只有一件然後被出售兩次,形成數據幻讀。html
分佈式鎖的處理方案有:redis
使用redis操做,數據庫
使用zookeeper操做,緩存
數據庫方面操做(行鎖)併發
以上全部的操做都是至關於在多個客戶端之間放一把鎖,相似於線程之間爭奪鎖的過程。分佈式
三種方案比較:性能
從理解的難易程度角度(從低到高)線程
數據庫 > 緩存 > Zookeepercode
從實現的複雜性角度(從低到高)htm
Zookeeper >= 緩存 > 數據庫
從性能角度(從高到低)
緩存 > Zookeeper >= 數據庫
從可靠性角度(從高到低)
Zookeeper > 緩存 > 數據庫
具體的實現過程是:
1.用redis實現
可使用redis的set(key,1,30,Nx)命令(在redis 2.6以上版本支持),其中的key可使用這些客戶端都要操做產品的id號去實現。
那麼當解鎖時需刪除key,刪除key要注意避免出現以前線程執行的時間很長致使刪除key時刪除了後面的客戶端key。那麼這是要注意設置key-value時必定要將value設置爲對應線程的id號然後執行刪除對應線程或者客戶端的key。
2.用數據庫實現
一.基於數據庫表
最簡單的方式可能就是直接建立一張鎖表,當咱們要鎖住某個方法或資源時,咱們就在該表中增長一條記錄,想要釋放鎖的時候就刪除這條記錄。給某字段添加惟一性約束,若是有多個請求同時提交到數據庫的話,數據庫會保證只有一個操做能夠成功,那麼咱們就能夠認爲操做成功的那個線程得到了該方法的鎖,能夠執行方法體內容。
缺點:會引入數據庫單點、無失效時間、不阻塞、不可重入等問題
二.基於數據庫的排他鎖
若是使用的是MySql的InnoDB引擎,在查詢語句後面增長 for update
,數據庫會在查詢過程當中(須經過惟一索引查詢)給數據庫表增長排他鎖,咱們能夠認爲得到排它鎖的線程便可得到分佈式鎖,然後能夠經過 connection.commit() 操做來釋放鎖。
會引入數據庫單點、不可重入、沒法保證必定使用行鎖(部分狀況下MySQL自動使用表鎖而不是行鎖)、排他鎖長時間不提交致使佔用數據庫鏈接等問題。
優勢:
直接藉助數據庫,容易理解。
缺點:
3.使用zookeeper實現
借用大佬的博客:https://www.cnblogs.com/garfieldcgf/p/6380816.html