Spring事務的傳播屬性
前言
Spring在TransactionDefinition接口中規定了7種類型的事務傳播行為。事務傳播行為是Spring架構獨有的事務增強特性,他不屬于的事務實際提供方資料庫行為。這是Spring為我們提供的強大的工具箱,使用事務傳播行可以為我們的開發工作提供許多便利。但是人們對他的誤解也頗多,你一定也聽過“service方法事務最好不要嵌套”的傳言。要想正确的使用工具首先需要了解工具。
基礎概念
-
什麼是事務傳播行為?
事務傳播行為用來描述由某一個事務傳播行為修飾的方法被嵌套進另一個方法的時事務如何傳播。
用僞代碼說明:
1 @Transaction(Propagation=XXX)
2 public void methodA(){
3 methodB();
4 //doSomething
5 }
6
7 public void methodB(){
8 //doSomething
9 }
methodA中存在事務,他又調用了methodB。methodB事物的一些特性由methodA決定,這就是事務的傳播行為。
-
Spring中七種事務傳播行為
事務傳播行為類型 說明
PROPAGATION_REQUIRED 如果目前沒有事務,就建立一個事務,如果已經存在一個事務中,加入到這個事務中。這是最常見的選擇。
PROPAGATION_SUPPORTS 支援目前事務,如果目前沒有事務,就以非事務方式執行。
PROPAGATION_MANDATORY 使用目前的事務,如果目前沒有事務,就抛出異常。
PROPAGATION_REQUIRES_NEW 建立事務,如果目前存在事務,把目前事務挂起。
PROPAGATION_NOT_SUPPORTED 以非事務方式執行操作,如果目前存在事務,就把目前事務挂起。
PROPAGATION_NEVER 以非事務方式執行,如果目前存在事務,則抛出異常。
PROPAGATION_NESTED 如果目前存在事務,則在嵌套事務内執行。如果目前沒有事務,則執行與PROPAGATION_REQUIRED類似的操作。
定義非常簡單,也很好了解,下面我們就進入代碼測試部分,驗證我們的了解是否正确。
代碼驗證
第一種情況。内部均為 propagation = Propagation.REQUIRED
1 @Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.REPEATABLE_READ)
2 @Override
3 public void testTransactional() {
4 int insert = downloadImgDao.test1();
5 log.info("insert1 = {}", insert);
7 insert = downloadImgDao.test2();
8 log.info("insert2 = {}", insert);
9 }
10
11 @Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.REPEATABLE_READ)
12 @Override
13 public int test1() {
14 DownloadImg downloadImg = new DownloadImg();
15 downloadImg.setId(666L);
16 downloadImg.setLink("張三");
17 downloadImg.setLinkname("16");
18 int res = downloadImgMapper.insertSelective(downloadImg);
19 log.info("res1 = {}", res);
20 return res;
21 }
22
23
24 @Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.REPEATABLE_READ)
25 @Override
26 public int test2() {
27 DownloadImg downloadImg = new DownloadImg();
28 downloadImg.setId(888L);
29 downloadImg.setLink("李四");
30 downloadImg.setLinkname("18");
31 int res = downloadImgMapper.insertSelective(downloadImg);
32 log.info("res2 = {}", res);
33
34 int i = 5 / 0;
35 return res;
36 }
張三,李四插入均失敗。
第二種情況。内部一種為 propagation = Propagation.REQUIRED,一種為Propagation.REQUIRES_NEW
1 @Transactional(propagation = Propagation.REQUIRES_NEW, isolation = Isolation.REPEATABLE_READ)
3 public int test1() {
4 DownloadImg downloadImg = new DownloadImg();
5 downloadImg.setId(666L);
6 downloadImg.setLink("張三");
7 downloadImg.setLinkname("16");
8 int res = downloadImgMapper.insertSelective(downloadImg);
9 log.info("res1 = {}", res);
10 return res;
11 }
12
13
14 @Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.REPEATABLE_READ)
15 @Override
16 public int test2() {
17 DownloadImg downloadImg = new DownloadImg();
18 downloadImg.setId(888L);
19 downloadImg.setLink("李四");
20 downloadImg.setLinkname("18");
21 int res = downloadImgMapper.insertSelective(downloadImg);
22 log.info("res2 = {}", res);
24 int i = 5 / 0;
25 return res;
26 }
張三插入成功,李四插入失敗。
第三種情況。内部均為Propagation.REQUIRES_NEW
跟我們現象的是一樣的,如果哪個test異常,哪個就失敗,無異常的就成功。
還有一種情況是,外圍抛異常了,内部都不抛異常,兩種内部插入也都會成功。
結論
本程式是實驗了PROPAGATION_REQUIRED以及Propagation.REQUIRES_NEW。
事務預設以PROPAGATION_REQUIRED來隔離。
1: 如果内部是PROPAGATION_REQUIRED隔離級别,内部隻要一個方法出錯,那麼整個事務都會復原。
2: 如果内部有方法以Propagation.REQUIRES_NEW來隔離。那麼他會建立一個新的事務來運作,如果他抛異常了,并不會影響其他事務的以及外部的事務。
spring事務官方文檔:
https://docs.spring.io/spring/docs/5.2.6.RELEASE/spring-framework-reference/data-access.html#tx-propagation參考文檔:
https://segmentfault.com/a/1190000013341344原文位址
https://www.cnblogs.com/wenbochang/p/13050801.html