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

x軸是上鎖的資源,y軸是消耗的時間,
事務方塊隨著時間的流逝向下移動,
當碰觸x軸時資源加鎖,越過x軸時資源解鎖
上圖是對于方法a的事務形狀,我起名【 事務方塊】,很抱歉我不會做動圖,本文以動圖來表達最佳,
@Transactional
function a(){
對A表修改,耗時五秒
}
一、多事務
當一個方法呼叫多個被事務注解的子方法時情況是

上圖是對于方法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秒
二、大事務
@Transactional
function abc(){
this.a(){}
this.b(){}
this.c(){}
}
function a(){
對A表修改,耗時五秒
}
function b(){
對B表修改,耗時五秒
}
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三個表一起解鎖,
這就造成了以下情況
三、死鎖
有如下兩個方法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億份的行,可見使用行級鎖時事務方塊明顯變小,
四、名稱來歷
事務方塊的名字來歷是因為聯想到俄羅斯方塊,俄羅斯方塊是為了給方塊找一個位置放置,而事務方塊是為了給方塊找一個時間間隙執行通過,兩者目的不同,
很抱歉我不會做動圖,請自行聯想俄羅斯方塊下落的情況,
也可以類比成要過橋的車輛,橋寬度固定,有的車占用一車道,有的車占用兩車道,有的車占用半車道,
車的形狀多種多樣,如老式武裝三輪摩托車像ab方法的小車,大客車就是一車道的長車,自行車是半車道的小車,


類似的情形很多,可自行聯想,
轉載請註明出處,本文鏈接:https://www.uj5u.com/shujuku/1116.html
標籤:MySQL
上一篇:MySQL學習筆記七:常用函式
