Spring 事務傳播行為的使用
★關鍵日志
事務提交日志:
Transaction synchronization committing SqlSession
Transaction synchronization deregistering SqlSession
Transaction synchronization closing SqlSession
事務回滾日志:
Transaction synchronization resuming SqlSession
Transaction synchronization deregistering SqlSession
Transaction synchronization closing SqlSession
PROPAGATION詳解
不加事務:支持當前事務,如果沒有事務就以非事務方式運行。
PROPAGATION_REQUIRED -- 支持當前事務,如果當前沒有事務,就新建一個事務。這是最常見的選擇。
PROPAGATION_SUPPORTS -- 支持當前事務(即能查詢到update或insert,但是沒有提交的東西--事務方法都是等方法執行完才提交), 如果當前沒有事務,就以非事務方式執行。(在類中不加注解的情況下和不加事務是一樣的,類中加了注解就可以加此注解來實現不加注解的情況)
PROPAGATION_NOT_SUPPORTED -- 以非事務方式執行操作,如果當前存在事務,就把當前事務掛起。
PROPAGATION_NEVER -- 以非事務方式執行,如果當前存在事務,則拋出異常。
PROPAGATION_MANDATORY -- 支持當前事務,如果當前沒有事務,就拋出異常。
PROPAGATION_REQUIRES_NEW -- 新建事務,如果當前存在事務,把當前事務掛起。
PROPAGATION_NESTED -- 如果當前存在事務,則在嵌套事務內執行,如果執行失敗,內部事務(即 ServiceB#methodB) 將回滾到它執行前的 SavePoint(回滾本身)。
如果當前沒有事務,則進行與PROPAGATION_REQUIRED類似的操作。
事務及嵌套事務的理解:
1.Propagation.REQUIRED:同一個事務,一起成功或失敗。注意:REQUIRED方法內的事務方法,不應該try-catch 而不拋出異常。
2.Propagation.REQUIRES_NEW:完全是新的事務,回滾或提交不受外部影響。
3.Propagation.NESTED的嵌套事務理解 :
(1)回滾只是回滾內部方法本身,外部事務可以選擇回滾/提交(try-catch方式處理的不同處理)
PS:這點Propagation.REQUIRES_NEW也能做到。
(2)外部事務提交回滾/提交,它也進行回滾/提交(它成功時的提交是在外部事務提交時)。
PS:這點Propagation.REQUIRES_NEW做不到。
異常:Transaction rolled back because it has been marked as rollback-only原因
1.捕獲后又拋出了不回滾的異常(默認RuntimeException才回滾,而Exception不回滾)。
2.Propagation.REQUIRED A方法調用 Propagation.REQUIRED B方法,如果捕獲了B方法中的異常沒有拋出 或 捕獲后又拋出了不回滾的異常(默認Exception不回滾)。
Transactional的不回滾問題
1、檢查你方法是不是public的,public方法的Transactional注解才是有效的,才能控制事務。
2、Spring默認只對UnChecked異常(RuntimeException)回滾,對於Checked(Exception)異常不回滾。
你的異常類型是Checked異常。如果想check異常也想回滾怎么辦?
(1)注解上加rollbackFor=Exception.class
(2)對異常進行轉換,轉換成RuntimeException或自定義繼承RuntimeException的異常
3. 同一個類中的方法調用,內部方法的事務是沒有效果的。
如方法A沒加事務,方法B中加了事務(不管加的是什么類型的事務)。方法A調用方法B,這樣方法B中的事務是無效的。因為AOP只對A方法進行處理了,而不會對內部的B方法進行處理。
父類中加了Transactional注解,子類中會繼承。
現象:service層繼承了CommonSercice的方法默認。CommonSercice加了transaction注解,結果service層的每個方法都默認有了transaction注解(required)。
項目實踐(不一定遵守,怎么方便怎么用)
1.不在類中加@Transactional,只在用到的方法中加。
2.不用PROPAGATION_SUPPORTS,因為效果和不加是一樣的。
3.大多數事務:PROPAGATION_REQUIRED即可滿足要求,要有rollbackFor=Exception.class,格式統一如下:
@Transactional(propagation = Propagation.REQUIRED,rollbackFor=Exception.class)
