基于數(shù)據(jù)庫(kù)表(鎖表,很少使用)
最簡(jiǎn)單的方式可能就是直接創(chuàng)建一張鎖表,然后通過(guò)操作該表中的數(shù)據(jù)來(lái)實(shí)現(xiàn)了。當(dāng)我們想要獲得鎖的時(shí)候,就可以在該表中增加一條記錄,想要釋放鎖的時(shí)候就刪除這條記錄。 為了更好的演示,我們先創(chuàng)建一張數(shù)據(jù)庫(kù)表,參考如下:
當(dāng)我們想要獲得鎖時(shí),可以插入一條數(shù)據(jù):
當(dāng)需要釋放鎖的時(shí),可以刪除這條數(shù)據(jù):
基于悲觀鎖
悲觀鎖實(shí)現(xiàn)思路?
在對(duì)任意記錄進(jìn)行修改前,先嘗試為該記錄加上排他鎖(exclusive locking)。
如果加鎖失敗,說(shuō)明該記錄正在被修改,那么當(dāng)前查詢可能要等待或者拋出異常。 具體響應(yīng)方式由開(kāi)發(fā)者根據(jù)實(shí)際需要決定。
如果成功加鎖,那么就可以對(duì)記錄做修改,事務(wù)完成后就會(huì)解鎖了。
其間如果有其他對(duì)該記錄做修改或加排他鎖的操作,都會(huì)等待我們解鎖或直接拋出異常。
以MySQL InnoDB中使用悲觀鎖為例?
要使用悲觀鎖,我們必須關(guān)閉mysql數(shù)據(jù)庫(kù)的自動(dòng)提交屬性,因?yàn)镸ySQL默認(rèn)使用autocommit模式,也就是說(shuō),當(dāng)你執(zhí)行一個(gè)更新操作后,MySQL會(huì)立刻將結(jié)果進(jìn)行提交。set autocommit=0;
上面的查詢語(yǔ)句中,我們使用了select…for update的方式,這樣就通過(guò)開(kāi)啟排他鎖的方式實(shí)現(xiàn)了悲觀鎖。此時(shí)在t_goods表中,id為1的 那條數(shù)據(jù)就被我們鎖定了,其它的事務(wù)必須等本次事務(wù)提交之后才能執(zhí)行。這樣我們可以保證當(dāng)前的數(shù)據(jù)不會(huì)被其它事務(wù)修改。
上面我們提到,使用select…for update會(huì)把數(shù)據(jù)給鎖住,不過(guò)我們需要注意一些鎖的級(jí)別,MySQL InnoDB默認(rèn)行級(jí)鎖。行級(jí)鎖都是基于索引的,如果一條SQL語(yǔ)句用不到索引是不會(huì)使用行級(jí)鎖的,會(huì)使用表級(jí)鎖把整張表鎖住,這點(diǎn)需要注意。
基于樂(lè)觀鎖
樂(lè)觀并發(fā)控制(又名“樂(lè)觀鎖”,Optimistic Concurrency Control,縮寫(xiě)“OCC”)是一種并發(fā)控制的方法。它假設(shè)多用戶并發(fā)的事務(wù)在處理時(shí)不會(huì)彼此互相影響,各事務(wù)能夠在不產(chǎn)生鎖的情況下處理各自影響的那部分?jǐn)?shù)據(jù)。在提交數(shù)據(jù)更新之前,每個(gè)事務(wù)會(huì)先檢查在該事務(wù)讀取數(shù)據(jù)后,有沒(méi)有其他事務(wù)又修改了該數(shù)據(jù)。如果其他事務(wù)有更新的話,正在提交的事務(wù)會(huì)進(jìn)行回滾。
以使用版本號(hào)實(shí)現(xiàn)樂(lè)觀鎖為例?
使用版本號(hào)時(shí),可以在數(shù)據(jù)初始化時(shí)指定一個(gè)版本號(hào),每次對(duì)數(shù)據(jù)的更新操作都對(duì)版本號(hào)執(zhí)行+1操作。并判斷當(dāng)前版本號(hào)是不是該數(shù)據(jù)的最新的版本號(hào)。
需要注意的是,樂(lè)觀鎖機(jī)制往往基于系統(tǒng)中數(shù)據(jù)存儲(chǔ)邏輯,因此也具備一定的局限性。由于樂(lè)觀鎖機(jī)制是在我們的系統(tǒng)中實(shí)現(xiàn)的,對(duì)于來(lái)自外部系統(tǒng)的用戶數(shù)據(jù)更新操作不受我們系統(tǒng)的控制,因此可能會(huì)造成臟數(shù)據(jù)被更新到數(shù)據(jù)庫(kù)中。在系統(tǒng)設(shè)計(jì)階段,我們應(yīng)該充分考慮到這些情況,并進(jìn)行相應(yīng)的調(diào)整(如將樂(lè)觀鎖策略在數(shù)據(jù)庫(kù)存儲(chǔ)過(guò)程中實(shí)現(xiàn),對(duì)外只開(kāi)放基于此存儲(chǔ)過(guò)程的數(shù)據(jù)更新途徑,而不是將數(shù)據(jù)庫(kù)表直接對(duì)外公開(kāi))。
缺陷
對(duì)數(shù)據(jù)庫(kù)依賴,開(kāi)銷問(wèn)題,行鎖變表鎖問(wèn)題,無(wú)法解決數(shù)據(jù)庫(kù)單點(diǎn)和可重入的問(wèn)題。