MySQL系列之鎖

2021-10-24 17:02:53 字數 3000 閱讀 5999

分布式鎖

疑問??什麼是共享鎖??

共享鎖=共享讀鎖,排他鎖=獨佔寫鎖

鎖機制與innodb鎖演算法

在關係型資料庫中,可以按照鎖的粒度把資料庫鎖分為行級鎖(innodb引擎)、表級鎖(myisam引擎)和頁級鎖(bdb引擎 )

myisam採用表級鎖(table-level locking)。innodb支援行級鎖(row-level locking)和表級鎖,預設為行級鎖。

innodb實現了行級鎖,頁級鎖,表級鎖。

行級鎖,表級鎖和頁級鎖對比

行鎖如何實現?

innodb是基於索引來完成行鎖

select * from tab_with_index where id = 1 for update;

-- for update 可以根據條件來完成行鎖鎖定,並且 id 是有索引鍵的列,如果 id不是索引鍵那麼innodb將完成表鎖,併發將無從談起

鎖演算法:3種

record lock:單個行記錄上的鎖

gap lock:間隙鎖,鎖定乙個範圍,不包括記錄本身

為了阻止多個事務將記錄插入到同一範圍內,這會導致幻讀問題。

next-key lock:record+gap 鎖定乙個範圍,包含記錄本身

innodb對於行查詢採用此

何為死鎖?

兩個或多個事務在同一資源上相互占用,並請求鎖定對方的資源,從而導致惡性迴圈的現象。

常見的解決死鎖的方法

1、如果不同程式會併發訪問多個表,盡量約定以相同的順序訪問表,可以大大降低死鎖機會。

2、在同乙個事務中,盡可能做到一次鎖定所需要的所有資源,減少死鎖產生概率;

3、對於非常容易產生死鎖的業務部分,可以嘗試使用公升級鎖定顆粒度,通過表級鎖定來減少死鎖產生的概率;

如果業務處理不好可以用分布式事務鎖或者使用樂觀鎖

先來看看功能:

分布式鎖使用者位於不同的機器中,所獲取成功後,才可以對共享資源進行操作

鎖具有重入的功能:即乙個使用者可以多次獲取某個鎖

獲取鎖有超時的功能:超過指定的時間,還未獲取成功,則返回獲取失敗

自動容錯功能:a機器獲取鎖lock1之後,在釋放lock1之前,機器a掛掉了,導致鎖lock1還未釋放。結果就是lock1一直被機器a占有。分布式鎖能自動解決:持有鎖規定持有超時時間,超時還未釋放時,其餘機器將爭奪該鎖。

假設不會發生併發衝突,只在提交操作時檢查是否違反資料完整性。在修改資料的時候把事務鎖起來,通過version的方式來進行鎖定。

實現方式:一般會使用版本號機制或cas演算法實現。

在修改表中資料記錄過程如下:

select獲取記錄r1

對r1進行編輯

update更新r1

存在什麼問題呢?

當a、b兩個執行緒同時執行到步驟1,這倆獲取的r1資料是一致的,然後同時執行步驟2,最後執行步驟3,最終2個執行緒都會更新成功。

但是後乙個執行的執行緒會把前乙個執行緒更新update的結果給覆蓋掉,這就是併發修改資料的問題

如何解決呢?

在表中新增乙個版本號,每次更新資料時將版本號作為條件,執行一次更新就版本號+1,過程優化一下,如下:

開啟事務start transaction

select獲取記錄r1,宣告變數v=r1.version

對r1進行編輯

執行更新update

update r1 set version=version+1 where user_id=#user_id# and version=#v#;

步驟4中更新update返回影響的行數,將其記錄在count中,然後根據count來判斷提交事務?回滾事務?

if

(count==1)

else

步驟4中,當多個執行緒同時執行到步驟2時,獲取到的記錄r1是一樣的,但當執行到步驟4時,資料庫對update的這行資料加鎖,確保併發情況下排隊執行

故只有第一次執行update更新操作會返回1,其餘執行緒的更新update操作回返回0,根據count值確定事務提交 / 回滾

所有執行緒執行select查詢時,執行緒的資料v都是r1記錄的版本:v=r1.version

但經過一次更新update後,r1記錄+1,但其餘執行緒的資料v還是原始的version資料,故不可能執行。

update r1 set version=version+1 where user_id=#user_id# and version=#v#;

上面這種利用版本號的方式就是樂觀鎖,確保了資料併發修改過程中正確性

考慮⼀個問題:⽐如a機會獲取了key1的鎖,並設定持有鎖的超時時間為10秒,但是獲取鎖之後,執⾏了⼀段業務操作,業務操作耗時超

過10秒了,此時機器b去獲取鎖時可以獲取成功的,此時會導致a、b兩個機器都獲取鎖成功了,都在執⾏業務操作,這種情況應該怎麼處

理?假定會發生併發衝突,遮蔽一切可能違反資料完整性的操作。在查詢完資料的時候就把事務鎖起來,直到提交事務。

實現方式:使用資料庫中的鎖機制

應用場景:

樂觀鎖多讀,悲觀鎖多寫

Mysql系列之鎖機制

一般乙個程式滿,從消耗的角度,乙個是cpu,乙個是io,但有的時候mysql慢,是因為某條sql不小心把整個表給鎖了。鎖是計算機協調多個程序或執行緒併發訪問某一資源的機制。在資料庫中,除了傳統的計算機資源 如cpu,ram,i o 的爭用外,資料也是供很多使用者共享的資源。如何保證資料併發訪問的一致...

MySQL鎖系列(四)之 undo log

1 redo 記錄的是對頁的重做日誌,undo 記錄的是對事務的逆向操作 2 undo 會產生redo,undo的產生也會伴隨這redo的產生,因為重啟恢復的時候,可以通過redo還原這些undo的操作,以達到回滾的目的1 用於對事務的回滾 2 用於mvcc 在mysql5.1的年代,乙個mysql...

MYSQL系列之 鎖與死鎖

mysql 裡面的鎖大致可以分成全域性鎖 表級鎖和行鎖三類 全域性鎖mysql 提供了乙個加全域性讀鎖的方法,命令是 flush tables with read lock ftwrl 當你需要讓整個庫處於唯讀狀態的時候,可以使用這個命令,之後其他執行緒的以下語句會被阻塞 資料更新語句 資料的增刪改...