spring事務整理(隔離級別,傳播行為,事務失效)與mvcc

事務(Transaction)是并發控制的單位,是用戶定義的一個操作序列。這些操作要么都做,要么都不做,是一個不可分割的工作單位

事務的隔離級別

臟讀:事務1更新數據,未提交時,事務2讀取,事務2讀取的是事務1修改后的值,此時事務1出錯回滾,導致事務2臟讀;
不可重復讀:事務1多次查詢,查詢1與查詢2期間,事務2修改了數據并提交,事務1中查詢1與查詢2獲取的數據不一致
幻讀:事務1多次查詢,查詢1與查詢2期間,事務2新增了數據,事務1中查詢1與查詢2獲取的數據不一致

  • READ UNCOMMITTED(讀未提交): 事務執行時可以看到其他事務“沒有提交的新增+修改”記錄。可以讀到一個事務的中間過程,違背了事務的隔離性,基本不會使用。
    結果:導致臟讀,導致不可重復讀,導致幻讀
  • READ COMMITTED (讀已提交) : 事務執行時可以看到其他事務“已經提交的新增+修改”記錄。
    結果:避免臟讀,導致不可重復讀,可能導致幻讀
  • REPEATABLE READ(可重復讀): 事務執行時可以看到其他事務“已經提交的新增”記錄。
    結果:避免臟讀,避免不可重復讀,可能導致幻讀(mvcc機制優化)(了解間隙鎖,也可解決幻讀)
  • SERIALIZABLE (串行化): 事務執行時看不到其他事務對數據庫所做的更新。兩個事務實際上是串行化方式運行。
    結果:避免臟讀,避免不可重復讀,避免幻讀

Spring隔離界別體現

@Transactional(isolation = Isolation.DEFAULT)
Isolation.DEFAULT 即默認與數據庫一致
查看mysql數據庫隔離級別
SELECT @@GLOBAL.transaction_isolation, @@transaction_isolation;
Mysql默認的事務隔離級別是REPEATABLE-READ。

SERIALIAZABLE如何保證隔離級別

SERIALIAZABLE事務隔離級別采用使用 2PL(Two-Phase Locking,兩階段鎖)機制來控制本地事務的并發,保證隔離性。2PL 是將鎖操作分為加鎖和解鎖兩個階段,并且保證兩個階段完全不相交。加鎖階段,只加鎖,不放鎖。解鎖階段,只放鎖,不加鎖。在一個本地事務中,每執行一條更新操作之前,都會先獲取對應的鎖資源,只有獲取鎖資源成功才會執行該操作,并且一旦獲取了鎖資源就會持有該鎖資源直到本事務執行結束。MySQL 通過這種 2PL 機制,可以保證在本地事務執行過程中,其他并發事務不能操作相同資源,從而實現了事務隔離。由于讀寫都需要上鎖,性能差。

MVCC(Multi Version Concurrency Control,多版本并發控制)

mvcc查用快照版本,增刪改用最新版本,超賣等場景解決方案之一
MySql通過內部機制避免幻讀,在rr隔離級別下幾乎達到了串行化隔離級別的效果。
InnoDB是在undolog中實現的MVCC,通過undolog可以找回數據的歷史版本。
MVCC只在 READ COMMITTED 和 REPEATABLE READ 兩個隔離級別下工作。其他兩個隔離級別和MVCC不兼容, 因為 READ UNCOMMITTED 總是讀取最新的數據行, 而不是符合當前事務版本的數據行。而 SERIALIZABLE 則會對所有讀取的行都加鎖。
InnoDB存儲引擎在數據庫每行數據的后面添加了三個字段
事務ID(DB_TRX_ID)字段: 用來標識最近一次對本行記錄做修改(insert|update)的事務的標識符, 即最后一次修改(insert|update)本行記錄的事務id。
回滾指針(DB_ROLL_PTR)字段: 指寫入回滾段(rollback segment)的 undo log record (撤銷日志記錄)。
DB_ROW_ID字段: 表中沒有主鍵或合適的唯一索引, 也就是無法生成聚簇索引的時候, InnoDB會幫我們自動生成聚集索引, 聚簇索引會使用DB_ROW_ID的值來作為主鍵; 如果我們有自己的主鍵或者合適的唯一索引, 那么聚簇索引中也就不會包含 DB_ROW_ID 了。
對于刪除操作,mysql底層會記錄好被刪除的數據行的回滾事務id,對于更新操作,mysql底層會新增一條相同數據并記錄好對應的事務id。

在RR級別下,快照讀(簡單的select操作)是通過MVVC和undo log來實現的
當前讀(select ... lock in share mode,select ... for update,insert,update,delete)是通過加record lock(記錄鎖)和gap lock(間隙鎖)來實現的。

事務的傳播行為

1:PROPAGATION_REQUIRED
如果當前沒有事務,就新建一個事務,如果已經存在一個事務中,則加入該事務。
比如說,ServiceB.methodB的事務級別定義為PROPAGATION_REQUIRED, 那么由于執行ServiceA.methodA的時候,ServiceA.methodA已經起了事務,這時調用ServiceB.methodB,ServiceB.methodB看到自己已經運行在ServiceA.methodA的事務內部,就不再起新的事務。而假如ServiceA.methodA運行的時候發現自己沒有在事務中,他就會為自己分配一個事務。這樣,在ServiceA.methodA或者在ServiceB.methodB內的任何地方出現異常,事務都會被回滾。即使ServiceB.methodB的事務已經被提交,但是ServiceA.methodA在接下來fail要回滾,ServiceB.methodB也要回滾。
2:PROPAGATION_SUPPORTS
如果當前在事務中,即以事務的形式運行,如果當前不再一個事務中,那么就以非事務的形式運行
3:PROPAGATION_MANDATORY
必須在一個事務中運行,否則就要拋出異常。
4:PROPAGATION_REQUIRES_NEW
新建事務,如果當前事務存在,則把當前事務掛起
比如我們設計ServiceA.methodA的事務級別為PROPAGATION_REQUIRED,ServiceB.methodB的事務級別為PROPAGATION_REQUIRES_NEW,那么當執行到ServiceB.methodB的時候,ServiceA.methodA所在的事務就會掛起,ServiceB.methodB會起一個新的事務,等待ServiceB.methodB的事務完成以后,他才繼續執行。他與PROPAGATION_REQUIRED 的事務區別在于事務的回滾程度了。因為ServiceB.methodB是新起一個事務,那么就是存在兩個不同的事務。如果ServiceB.methodB已經提交,那么ServiceA.methodA失敗回滾,ServiceB.methodB是不會回滾的。如果ServiceB.methodB失敗回滾,如果他拋出的異常被ServiceA.methodA捕獲,ServiceA.methodA事務仍然可能提交。
5: PROPAGATION_NOT_SUPPORTED
以非事務方式執行操作,如果當前存在事務,就把當前事務掛起。
比如ServiceA.methodA的事務級別是PROPAGATION_REQUIRED ,而ServiceB.methodB的事務級別是PROPAGATION_NOT_SUPPORTED ,那么當執行到ServiceB.methodB時,ServiceA.methodA的事務掛起,而他以非事務的狀態運行完,再繼續ServiceA.methodA的事務。
6:PROPAGATION_NEVER
以非事務方式執行操作,如果當前存在事務,則拋出異常。
假設ServiceA.methodA的事務級別是PROPAGATION_REQUIRED, 而ServiceB.methodB的事務級別是PROPAGATION_NEVER ,那么ServiceB.methodB就要拋出異常了。
7:PROPAGATION_NESTED
理解Nested的關鍵是savepoint。他與PROPAGATION_REQUIRES_NEW的區別是,PROPAGATION_REQUIRES_NEW另起一個事務,將會與他的父事務相互獨立,而Nested的事務和他的父事務是相依的,他的提交是要等和他的父事務一塊提交的。也就是說,如果父事務最后回滾,他也要回滾的。而Nested事務的好處是他有一個savepoint。

解決Transactional注解不回滾

1、檢查你方法是不是public的,不能作用在方法的內部的任何方法上
2、你的異常類型是不是unchecked異常,即運行時異常 (java里面將派生于Error或者RuntimeException(比如空指針,數組越界,1/0)的異常稱為unchecked異常,其他繼承自java.lang.Exception得異常統稱為Checked Exception,如IOException、TimeoutException等)。如果想check異常也想回滾怎么辦,注解上面寫明異常類型即可@Transactional(rollbackFor=Exception.class)。類似的還有norollbackFor,自定義不回滾的異常
3、數據庫引擎要支持事務,如果是MySQL,注意表要使用支持事務的引擎,比如innodb,如果是myisam,事務是不起作用的
4、是否開啟了對注解的解析(Springboot不需關注,Springboot會自動配置,5同)
<tx:annotation-driven transaction-manager="transactionManager" proxy-target-class="true"/>
5、spring是否掃描到你這個包,如下是掃描到org.test下面的包
<context:component-scan base-package="org.test" ></context:component-scan>
6、檢查是不是同一個類中的方法調用(如a方法調用同一個類中的b方法)
7、異常是不是被你catch住了

解決不能作用在方法的任何內部方法上

1.注入本身service,在當前處理service注入自己,然后內部調用 推薦
2.(1).在未定義事務的方法調用帶有事務的方法使用AopContext.currentProxy()((AfterSaleManager)AopContext.currentProxy()).innerRefund(goodsReturnsApply); 可用
(2).spring配置文件配置
<aop:aspectj-autoproxy expose-proxy="true"/>
3、重新定義對象 applicationContext.getBean() 未測試
4、使用@Aspect注解 未測試
希望在編譯期間進行織入(weaving),還是編譯后(post-compile)或是運行時(run-time)。Spring只支持運行時織入,你可以選擇使用AspectJ編譯后(post-compile)或載入時(load-time)織入。Spring基于代理模式(使用CGLIB),它有一個使用限制,即無法在使用final修飾的bean上應用橫切關注點。

借鑒:https://juejin.im/post/5b90cbf4e51d450e84776d27

https://blog.csdn.net/wwh578867817/article/details/51736723

https://segmentfault.com/a/1190000012650596

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 229,698評論 6 539
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,202評論 3 426
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 177,742評論 0 382
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,580評論 1 316
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,297評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,688評論 1 327
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,693評論 3 444
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,875評論 0 289
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,438評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,183評論 3 356
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,384評論 1 372
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,931評論 5 363
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,612評論 3 348
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,022評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,297評論 1 292
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,093評論 3 397
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,330評論 2 377

推薦閱讀更多精彩內容