事務的本質和死鎖的原理

僅以MySQL和Spring爲例,本文不介紹事務和鎖的概念。
本文使用僞代碼表示方法代碼,僅僅表達方法的意義及事務註解
〇、事務的形狀
在我心中,事務一直是這個樣子的

x軸是上鎖的資源,y軸是消耗的時間,
事務方塊隨着時間的流逝向下移動,
當碰觸x軸時資源加鎖,越過x軸時資源解鎖
上圖是對於方法a的事務形狀,我起名【 事務方塊】,很抱歉我不會作動圖,本文以動圖來表達最佳。併發

@Transactional
function a(){
    對A表修改,耗時五秒
}
1、多事務
當一個方法調用多個被事務註解的子方法時狀況是

上圖是對於方法abc調用時,a方法、b方法、c方法的事務形狀
function abc(){
    this.a(){}
    this.c(){}
}
@Transactional
function a(){
    對A表修改,耗時五秒
}
@Transactional
function b(){
    對B表修改,耗時五秒
}
@Transactional
function c(){
    對C表修改,耗時五秒
}
其中abc方法開始執行時,執行到a方法,鎖定a表,當a方法結束b方法開始時,a表解鎖,b表鎖定,當b方法結束c方法開始時,b表解鎖c表鎖定。
至關於下圖的三個事務方塊聯合且相對位置鎖定一塊兒下落,總運行時間15秒

若是併發請求兩次abc方法則事務方塊以下圖

其中a表會先被請求1鎖定5秒後解鎖,再被請求2鎖定5秒,
其中b表也會先被請求1鎖定5秒後解鎖,再被請求2鎖定5秒,
其中c表也會先被請求1鎖定5秒後解鎖,再被請求2鎖定5秒,
而請求1在解鎖表a後緊接着又鎖定了表b五秒,同時表a再被請求2鎖定5秒
依次類推,請求2都在請求1解鎖對應的表以後,鎖定該表,
那麼總運行時間20秒
2、大事務
@Transactional
function abc(){
    this.a(){}
    this.b(){}
    this.c(){}
}this

function a(){
    對A表修改,耗時五秒
}3d

function b(){
    對B表修改,耗時五秒
}code

function c(){
    對C表修改,耗時五秒
}
其中abc方法上有事務註解,而子方法a、b、c上沒有事務註解,事務方塊形狀以下圖

a、b、c三個顏色的方塊是結合在一塊兒的只能一塊兒執行,那麼a表被鎖定15秒,b表被鎖定10秒,c表被鎖定5秒
若是也併發請求兩次abc方法則總耗時30秒,顯而易見事務方塊越大,耗時越長。
在這個abc方法中,事務鎖定表是懶鎖定的方式,就是說
當abc中a方法開始執行時,只鎖定了a表,執行完a方法後,
開始執行b方法鎖定b表,此時a表不解鎖,當b方法執行完後,
開始執行c方法鎖定c表,此時a、b兩個表都不解鎖,當c方法執行完後,a、b、c三個表一塊兒解鎖。
這就形成了如下狀況
3、死鎖
有以下兩個方法ab和ba
@Transactional
function ab(){
    this.a(){}
    this.b(){}
}
@Transactional
function ba(){
    this.b(){}
    this.a(){}
}
當ab和ba方法同時被執行時,事務方塊相似下圖,但不徹底

當ab和ba方法同時被執行時,ab鎖定a表,ba鎖定b表,
當ab執行完a方法請求鎖定b表時,ba也執行完了b方法請求鎖定a表,
但ab沒有解開對a表的鎖定,ba也沒有解開對b表的鎖定,那麼相互等待對方解鎖,這就是死鎖。
因此減小死鎖出現的概率的辦法是減少事務方塊的大小,即減少事務方塊消耗的時間或減少事務方塊鎖定的資源【表或行】
因此行級鎖不易出現死鎖,表級鎖易出現死鎖,是由於行級鎖事務方塊小,但消耗時間不必定,仍是須要參考事務消耗時間。
若是主鍵是int類型自增id,則至關於把事務可鎖定資源從一個表分紅了21億份的行,可見使用行級鎖時事務方塊明顯變小。
4、名稱來歷
事務方塊的名字來歷是由於聯想到俄羅斯方塊,俄羅斯方塊是爲了給方塊找一個位置放置,而事務方塊是爲了給方塊找一個時間間隙執行經過,二者目的不一樣,
很抱歉我不會作動圖,請自行聯想俄羅斯方塊下落的狀況。
也能夠類比成要過橋的車輛,橋寬度固定,有的車佔用一車道,有的車佔用兩車道,有的車佔用半車道,
車的形狀多種多樣,如老式武裝三輪摩托車像ab方法的小車,大客車就是一車道的長車,自行車是半車道的小車,


相似的情形不少,可自行聯想。blog

相關文章
相關標籤/搜索