行鎖顧名思義,就是針對單行資料加鎖,在mysql中,鎖的實作是由引擎層實作的,MyISAM引擎就不支持行鎖
不支持行鎖就意味著并發控制只能使用表鎖,也就是說同一時間,在這個表上只能有一個更新在執行,這就會
影響到業務的并發度。InnoDB是支持行鎖的,這也是MyISAM被InnoDB替代的重要原因之一。
兩階段鎖協議
先舉個例子,事務B的陳述句執行的時候會發生什么現象?這取決于事務A在執行完兩條陳述句后持有那些鎖,以及在什么時候釋放?
大家可以自己做個實驗,是這樣的,事務B在執行這條陳述句時會被阻塞,大家會不會有疑惑,
前面兩條陳述句不是執行完了嗎?
為什么還會阻塞?
其實事務A的加鎖時機是執行第一條陳述句的時候,釋放鎖的時候是commit完以后
但是事務B是在事務A commit前執行的
這個時候事務A還持有id=1這行資料的鎖,所以事務B會被阻塞。
知道了這個原理對于我們有什么啟示呢?
既然知道了鎖的釋放是在commit之后
那么我們就可以把最可能造成鎖沖突
最可能影響并發度的鎖盡量往后放
舉個例子:
業務:顧客A要在影院B買一張電影票
操作:
1.從顧客A的賬戶余額中減掉電影票的價格
2.將影院B的賬戶余額增加這張電影票價
3.增加一條操作日志
大家想想看,這三個操作,那個最容易影響到并發度會造成鎖沖突
很明顯是第二個操作,為啥呢?想想看操作1中只是鎖了這個用戶的
這行資料,只對他自己有影響,這個時候如果有個顧客C也買了電影
票,那么這個時候的沖突就是操作2了,因為人家也需要更新影院的
賬戶余額,所以我們要把操作2放在最后執行,因為這樣對操作2涉及的
行鎖,鎖住時間就會少一點,最大程度的減少了事務之間的等待
提升了并發度。
死鎖和死鎖檢測
如圖所示,事務A在等待事務B釋放id=2的鎖,事務B在等待事務A釋放id=1的鎖
這種情況就是死鎖
發生死鎖有兩種方法解決
1.直接進入等待,直到超時。這個超時時間可以通過引數innodb_lock_wait_timeout來設定
2.發起死鎖檢測,發現死鎖后,主動回滾死鎖鏈條中的某一個事務,讓其他事務得以執行。
將引數innodb_deadlock_detect設定為on,表示開啟這個邏輯
在innodb中,innodb_lock_wait_timeout的值默認是50s,以為著如果使用第一種方法,
第一個被鎖住的執行緒要過50s才會超時退出,然后其他執行緒才有可能繼續執行。
對于在線服務來說,這個等待時間往往是無法接受的。
但是我們又不能把這個時間設定的很小,比如1s,如果這個時候不是死鎖,而是正常的鎖等待呢
這樣就會造成很多誤傷,所以我們還是使用死鎖檢測好一些,好在innodb_deadlock_detect默認就是on
其實死鎖檢測也是會占用很多cpu資源的,當事務被鎖住的時候,就要看看它鎖依賴的執行緒有沒有被別人鎖住
如此回圈,最后判斷是否出現了回圈等待,也就是死鎖

uj5u.com熱心網友回復:
如果業務層面不好解決這個問題,可以采用一個方法:1. 加一個冗余列
2. 事務一開始就同時更新這兩條記錄的冗余列,條件用 id IN(1,2),這樣就把兩條記錄一起鎖定了。
但是性能會低。
轉載請註明出處,本文鏈接:https://www.uj5u.com/shujuku/60890.html
標籤:MySQL
上一篇:SQL技術內幕:InnoDB存盤引擎 高性能MySQL 這兩本書推薦哪個??
下一篇:CentOS6.9 (MySql v5.7.22) 使用mysql C API mysql_real_query 導致記憶體溢位
