事務的本質(zhì)和死鎖的原理
本文來自讀者投稿?
作者:依波拉?
原文:https://www.cnblogs.com/klarck/p/13630990.html
僅以MySQL和Spring為例,本文不介紹事務和鎖的概念。
本文使用偽代碼表示方法代碼,僅僅表達方法的意義及事務注解。
事務的形狀
在我心中,事務一直是這個樣子的
![性能優(yōu)化2020013[00_00_00--00_00_05].gif](https://filescdn.proginn.com/9c19e563f8f251333ff160b12f8770c0/f9e0c34b4dabb932c23622827e6d3905.webp)
x軸是上鎖的資源,y軸是消耗的時間,
事務方塊隨著時間的流逝向下移動,
當碰觸x軸時資源加鎖,越過x軸時資源解鎖
上圖是對于方法a的事務形狀,我起名【 事務方塊】。
@Transactionalfunction a(){對A表修改,耗時五秒}
? 一、多事務
當一個方法調(diào)用多個被事務注解的子方法時情況是
![性能優(yōu)化2020013[00_00_05--00_00_19].gif](https://filescdn.proginn.com/64d5ab7e1c0987d0a16616bd60fbfc1c/e17ba406e1ff575177a5d36ca41a2bfb.webp)
上圖是對于方法abc調(diào)用時,a方法、b方法、c方法的事務形狀
function abc(){this.a(){}this.c(){}}@Transactionalfunction a(){對A表修改,耗時五秒}@Transactionalfunction b(){對B表修改,耗時五秒}@Transactionalfunction c(){對C表修改,耗時五秒}
其中abc方法開始執(zhí)行時,執(zhí)行到a方法,鎖定a表,當a方法結(jié)束b方法開始時,a表解鎖,b表鎖定,當b方法結(jié)束c方法開始時,b表解鎖c表鎖定。
相當于下圖的三個事務方塊聯(lián)合且相對位置鎖定一起下落,總運行時間15秒
![性能優(yōu)化2020013[00_00_20--00_00_34].gif](https://filescdn.proginn.com/a24a49e4fe1f159a2598af2ad9efacf1/19d902c1da3b7984f08917436072da72.webp)
如果并發(fā)請求兩次abc方法則事務方塊如下圖
![性能優(yōu)化2020013[00_00_36--00_00_55].gif](https://filescdn.proginn.com/dc6f009716b177f0a340b407972e3178/76de931b779b25e09c49d40d38b5a413.webp)
其中a表會先被請求1鎖定5秒后解鎖,再被請求2鎖定5秒,
其中b表也會先被請求1鎖定5秒后解鎖,再被請求2鎖定5秒,
其中c表也會先被請求1鎖定5秒后解鎖,再被請求2鎖定5秒,
而請求1在解鎖表a后緊接著又鎖定了表b五秒,同時表a再被請求2鎖定5秒
依次類推,請求2都在請求1解鎖對應的表之后,鎖定該表,
那么總運行時間20秒。
? 二、大事務
@Transactionalfunction abc(){this.a(){}this.b(){}this.c(){}}function a(){對A表修改,耗時五秒}function b(){對B表修改,耗時五秒}function c(){對C表修改,耗時五秒}
其中abc方法上有事務注解,而子方法a、b、c上沒有事務注解,事務方塊形狀如下圖
![性能優(yōu)化2020013[00_00_56--00_01_00].gif](https://filescdn.proginn.com/da19f77576d053a37bf12b96969b1e67/b6110dce206682f5906e85fba771d9d4.webp)
a、b、c三個顏色的方塊是結(jié)合在一起的只能一起執(zhí)行,那么a表被鎖定15秒,b表被鎖定10秒,c表被鎖定5秒
如果也并發(fā)請求兩次abc方法則總耗時30秒,顯而易見事務方塊越大,耗時越長。
在這個abc方法中,事務鎖定表是懶鎖定的方式,就是說
當abc中a方法開始執(zhí)行時,只鎖定了a表,執(zhí)行完a方法后,
開始執(zhí)行b方法鎖定b表,此時a表不解鎖,當b方法執(zhí)行完后,
開始執(zhí)行c方法鎖定c表,此時a、b兩個表都不解鎖,當c方法執(zhí)行完后,a、b、c三個表一起解鎖。
這就造成了以下情況。
? 三、死鎖
有如下兩個方法ab和ba
@Transactionalfunction ab(){this.a(){}this.b(){}}@Transactionalfunction ba(){this.b(){}this.a(){}}
當ab和ba方法同時被執(zhí)行時,事務方塊類似下圖,但不完全
![性能優(yōu)化2020013[00_01_02--00_01_15].gif](https://filescdn.proginn.com/61d4d3a085259c7cd1ade55104bf5d74/c774490852cbbdaa97163c9763eaea47.webp)
當ab和ba方法同時被執(zhí)行時,ab鎖定a表,ba鎖定b表,
當ab執(zhí)行完a方法請求鎖定b表時,ba也執(zhí)行完了b方法請求鎖定a表,
但ab沒有解開對a表的鎖定,ba也沒有解開對b表的鎖定,那么相互等待對方解鎖,這就是死鎖。
所以減少死鎖出現(xiàn)的幾率的辦法是減小事務方塊的大小,即減小事務方塊消耗的時間或減小事務方塊鎖定的資源【表或行】
所以行級鎖不易出現(xiàn)死鎖,表級鎖易出現(xiàn)死鎖,是因為行級鎖事務方塊小,但消耗時間不一定,還是需要參考事務消耗時間。
如果主鍵是int類型自增id,則相當于把事務可鎖定資源從一個表分成了21億份的行,可見使用行級鎖時事務方塊明顯變小。
? 四、名稱來歷
事務方塊的名字來歷是因為聯(lián)想到俄羅斯方塊,俄羅斯方塊是為了給方塊找一個位置放置,而事務方塊是為了給方塊找一個時間間隙執(zhí)行通過,兩者目的不同。
很抱歉我不會做動圖,請自行聯(lián)想俄羅斯方塊下落的情況。
也可以類比成要過橋的車輛,橋?qū)挾裙潭ǎ械能囌加靡卉嚨溃械能囌加脙绍嚨溃械能囌加冒胲嚨溃?/p>
車的形狀多種多樣,如老式武裝三輪摩托車像ab方法的小車,大客車就是一車道的長車,自行車是半車道的小車。類似的情形很多,可自行聯(lián)想。

推薦閱讀
(點擊標題可跳轉(zhuǎn)閱讀)
