一、事務的隔離級別
1、讀未提交Read Uncommited:事務還沒提交的時候,修改的數據就讓別的事務給讀到了----臟讀
2、讀已提交Read Commited:事務A查詢一個數據值是1,過了段時間,事務B把這個數據修改了還提交了,此時事務A再次查詢這個數據值變為2了
這是不可重復讀,一個事務內對一個數據兩次讀,可能會讀到不一樣的值;
3、可重復讀Read Repeatable:事務A在執行過程中,讀某個數據的值,無論讀多少次都是1,就算過程中事務B將這個數據的值修改並提交了,事務A讀到的還是自己事務開始時這個數據的值。
4、幻讀:幻讀針對的是插入。
某事務將所有記錄行的某字段改為了2,結果此時另外一個事務插入了一條數據,該字段默認值是1,突然發現有條數據的值是1,以為產生幻覺了
解決幻讀需要鎖表
5、串行化:解決幻讀就要使用串行化級別的隔離級別,所有事務串行起來,不允許多個事務並行操作
MYSQL默認隔離級別是可重復讀Read Repeatable,就是說每個事務都會開啟自己要操作的數據的快照,讀的都是快照數據,多次讀結果一樣;
MYSQL通過MVCC多版本並發控制(multi-version concurrency control) 機制來實現
二、事務不生效的場景
1.private、final、static方法,事務不生效,入口方法必須是public ,spring的AOp特性決定的,spring認為private自己用的方法應該自己控制,不應該用事務切進去
2、Spring的事務管理默認只對出現運行期異常(java.lang.RuntimeException及其子類)進行回滾(至於為什么spring要這么設計:因為spring認為Checked的異常屬於業務的,coder需要給出解決方案而不應該直接扔該框架)
3.同類調用不生效(service方法中調用本類中的另一個方法,事務沒有生效):
在同一個類中一個無事務的方法調用另一個有事務的方法,事務是不會起作用的
4.如果使用的是rollbakfor的默認,已檢查的異常(所有派生自Error和RuntimeException的類,都是未檢查異常.其余的是已檢查異常, 比如nullPointException是未檢查的,IllegalAccessException 是已檢查的)不回滾, 可設為rollbackFor={Exception.class}
5.最好不要把@trasaction注解到接口上:
在接口上使用 @Transactional 注解,只能當你設置了基於接口的代理時它才生效。因為注解是 不能繼承 的,這就意味着如果正在使用基於類的代理時,那么事務的設置將不能被基於類的代理所識別,而且對象也將不會被事務代理所包裝。
6、確認你的類是否被代理了(因為spring的事務實現原理為AOP,只有通過代理對象調用方法才能被攔截,事務才能生效
7、確保你的業務和事務入口在同一個線程里,否則事務也是不生效的