Transactional#Propagation事務(wù)傳播行為
事務(wù)傳播行為用來描述由某一個事務(wù)傳播行為修飾的方法被嵌套進另一個方法時事務(wù)如何傳播
一直對這7種傳播行為記得不是特別清楚,也容易混淆,本文通過具體的例子來驗證一下,每一種事務(wù)傳播行為的實際效果。
tip: 參數(shù)String method是為了一次運行多個單元測試方法,可以直接從數(shù)據(jù)庫知道哪個方法成功了
REQUIRED
@Transactional默認行為
在外圍方法未開啟事務(wù)的情況下Propagation.REQUIRED注解的內(nèi)部方法會新開啟自己的事務(wù),且開啟的事務(wù)相互獨立,互不干擾。
外圍方法開啟事務(wù)的情況下Propagation.REQUIRED注解的內(nèi)部方法會加入到外圍方法的事務(wù)中,所有Propagation.REQUIRED修飾的內(nèi)部方法和外圍方法均屬于同一事務(wù),只要一個方法回滾,整個事務(wù)均回滾。
/**
* @createDate:2019/6/14$14:02$
* @author: Heyfan Xie
*/
@Service
public class RequiredService {
private static final String TYPE = "required";
@Autowired
private RequiredUser1Service user1Service;
@Autowired
private RequiredUser2Service user2Service;
/**
* 外圍方法沒有事務(wù)
* 調(diào)用有事務(wù)的方法1
* 調(diào)用有事務(wù)的方法2
* 外圍方法拋出異常
* ------------------
* 結(jié)果:
* 方法1執(zhí)行成功
* 方法2執(zhí)行成功
*/
public void notransactionExceptionRequiredRequried() {
user1Service.addRequried(TYPE + 1);
user2Service.addRequried(TYPE + 1);
throw new RuntimeException();
}
/**
* 外圍方法沒有事務(wù)
* 調(diào)用有事務(wù)的方法1
* 調(diào)用有事務(wù)的方法2
* 方法2拋出異常
* ------------------
* 方法1執(zhí)行成功
* 方法2執(zhí)行回滾
*/
public void notransactionequiredRequriedException() {
user1Service.addRequried(TYPE + 2);
user2Service.addRequriedException(TYPE + 2);
}
/**
* 外圍方法有事務(wù)
* 調(diào)用有事務(wù)的方法1
* 調(diào)用有事務(wù)的方法2
* 外圍方法拋出異常
* ------------------
* 方法1執(zhí)行回滾
* 方法2執(zhí)行回滾
*/
@Transactional(propagation = Propagation.REQUIRED)
public void transactionExceptionRequiredRequired(){
user1Service.addRequried(TYPE + 3);
user2Service.addRequried(TYPE + 3);
throw new RuntimeException();
}
/**
* 外圍方法有事務(wù)
* 調(diào)用有事務(wù)的方法1
* 調(diào)用有事務(wù)的方法2
* 方法2拋出異常
* ------------------
* 方法1執(zhí)行回滾
* 方法2執(zhí)行回滾
*/
@Transactional(propagation = Propagation.REQUIRED)
public void transactionRequiredRequiredException(){
user1Service.addRequried(TYPE + 4);
user2Service.addRequriedException(TYPE + 4);
}
/**
* 外圍方法有事務(wù)
* 調(diào)用有事務(wù)的方法1
* try
* 調(diào)用有事務(wù)的方法2
* 方法2拋出異常
* catch
* ------------------
* 方法1執(zhí)行回滾
* 方法2執(zhí)行回滾
*/
@Transactional(propagation = Propagation.REQUIRED)
public void transactionRequiredRequiredExceptionTry(){
user1Service.addRequried(TYPE + 5);
try {
user2Service.addRequriedException(TYPE + 5);
} catch (Exception e) {
System.out.println("方法回滾");
}
}
}
@Service
public class RequiredUser1Service {
@Autowired
private User1Repository user1Repository;
@Transactional(propagation = Propagation.REQUIRED)
public void addRequried(String method) {
User1 user = new User1();
user.setName(method + "張三");
user1Repository.save(user);
}
}
@Service
public class RequiredUser2Service {
@Autowired
private User2Repository user2Repository;
@Transactional(propagation = Propagation.REQUIRED)
public void addRequried(String method) {
User2 user = new User2();
user.setName(method + "李四");
user2Repository.save(user);
}
@Transactional(propagation = Propagation.REQUIRED)
public void addRequriedException(String method) {
User2 user = new User2();
user.setName(method + "王五");
user2Repository.save(user);
throw new RuntimeException();
}
}
| 序號 | 驗證方法 | USER1 | USER2 | 分析 |
|---|---|---|---|---|
| 1 | 外圍方法沒有事務(wù),調(diào)用有事務(wù)的方法1,調(diào)用有事務(wù)的方法2,外圍方法拋出異常 | 成功 | 成功 | 外圍沒有開啟事務(wù),調(diào)用的方法分別在獨立的自己的事務(wù)內(nèi),外圍方法拋出異常不會影響到調(diào)用方法的的事務(wù),所以都能成功 |
| 2 | 外圍方法沒有事務(wù), 調(diào)用有事務(wù)的方法1,調(diào)用有事務(wù)的方法2 ,方法2拋出異常 | 成功 | 回滾 | 外圍沒有開啟事務(wù),調(diào)用的方法分別在獨立的自己的事務(wù)內(nèi),方法2拋出異常只會回滾本身的事務(wù)。 |
| 3 | 外圍方法有事務(wù), 調(diào)用有事務(wù)的方法1,調(diào)用有事務(wù)的方法2 ,外圍方法拋出異常 | 回滾 | 回滾 | 外圍有開啟事務(wù),調(diào)用的方法分別在獨立的自己的事務(wù)內(nèi),因為是required,所以都會加入到外圍事務(wù),全部都會回滾 |
| 4 | 外圍方法有事務(wù), 調(diào)用有事務(wù)的方法1,調(diào)用有事務(wù)的方法2 ,方法2拋出異常 | 回滾 | 回滾 | 外圍有開啟事務(wù),調(diào)用的方法分別在獨立的自己的事務(wù)內(nèi),因為是required,所以都會加入到外圍事務(wù),全部都會回滾 |
| 5 | 外圍方法有事務(wù), 調(diào)用有事務(wù)的方法1,調(diào)用有事務(wù)的方法2 ,方法2拋出異常,外圍方法捕獲異常 | 回滾 | 回滾 | 外圍有開啟事務(wù),調(diào)用的方法分別在獨立的自己的事務(wù)內(nèi),因為是required,所以都會加入到外圍事務(wù),全部都會回滾,由于捕獲了異常但是沒有拋出,會報錯: Transaction silently rolled back because it has been marked as rollback-only |
SUPPORTS
存在事務(wù),就加入到事務(wù)中;不存在事務(wù),就不創(chuàng)建自己的事務(wù)。
在外圍方法未開啟事務(wù)的情況下,Propagation.SUPPORTS注解的的方法會以無事務(wù)的方式運行。
在外圍方法開啟事務(wù)的情況下,Propagation.SUPPORTS注解的方法會加入當(dāng)前事務(wù)。
@Service
public class SupportUser1Service {
@Autowired
private User1Repository user1Repository;
@Transactional(propagation = Propagation.SUPPORTS)
public void addSupport(String method) {
User1 user = new User1();
user.setName(method + "張三");
user1Repository.save(user);
}
}
@Service
public class SupportUser2Service {
@Autowired
private User2Repository user2Repository;
@Transactional(propagation = Propagation.SUPPORTS)
public void addSupport(String method) {
User2 user = new User2();
user.setName(method + "李四");
user2Repository.save(user);
}
@Transactional(propagation = Propagation.SUPPORTS)
public void addSupportException(String method) {
User2 user = new User2();
user.setName(method + "王五");
user2Repository.save(user);
throw new RuntimeException();
}
}
| 序號 | 驗證方法 | USER1 | USER2 | 分析 |
|---|---|---|---|---|
| 1 | 外圍方法沒有事務(wù),調(diào)用有事務(wù)的方法1,調(diào)用有事務(wù)的方法2,外圍方法拋出異常 | 成功 | 成功 | 外圍方法沒有事務(wù),內(nèi)部的方法1,方法2以無事務(wù)的方式運行,所以拋出異常不會回滾 |
| 2 | 外圍方法沒有事務(wù), 調(diào)用有事務(wù)的方法1,調(diào)用有事務(wù)的方法2 ,方法2拋出異常 | 成功 | 成功 | 外圍方法沒有事務(wù),內(nèi)部的方法1,方法2以無事務(wù)的方式運行,所以拋出異常不會回滾 |
| 3 | 外圍方法有事務(wù), 調(diào)用有事務(wù)的方法1,調(diào)用有事務(wù)的方法2 ,外圍方法拋出異常 | 回滾 | 回滾 | 外圍方法有事務(wù),內(nèi)部的方法1,方法2加入外圍事務(wù)的方式運行,所以外圍方法拋出異常會回滾 |
| 4 | 外圍方法有事務(wù), 調(diào)用有事務(wù)的方法1,調(diào)用有事務(wù)的方法2 ,方法2拋出異常 | 回滾 | 回滾 | 外圍方法有事務(wù),內(nèi)部的方法1,方法2加入外圍事務(wù)的方式運行,所以方法2拋出異常會回滾 |
| 5 | 外圍方法有事務(wù), 調(diào)用有事務(wù)的方法1,調(diào)用有事務(wù)的方法2 ,方法2拋出異常,外圍方法捕獲異常 | 回滾 | 回滾 | 外圍方法有事務(wù),內(nèi)部的方法1,方法2加入外圍事務(wù)的方式運行,所以方法2拋出異常會回滾;由于捕獲了異常但是沒有拋出,會報錯: Transaction silently rolled back because it has been marked as rollback-only |
MANDATORY
只能運行在一個已經(jīng)存在的事務(wù)中,不能自己創(chuàng)建事務(wù)
在外圍方法未開啟事務(wù)的情況下,Propagation.MANDATORY注解的方法運行時會拋出錯誤:No existing transaction found for transaction marked with propagation 'mandatory'
在外圍方法開啟事務(wù)的情況下,Propagation.MANDATORY注解的方法會加入當(dāng)前事務(wù)。
@Service
public class MandatoryUser1Service {
@Autowired
private User1Repository user1Repository;
@Transactional(propagation = Propagation.MANDATORY)
public void addMandatory(String method) {
User1 user = new User1();
user.setName(method + "張三");
user1Repository.save(user);
}
}
@Service
public class MandatoryUser2Service {
@Autowired
private User2Repository user2Repository;
@Transactional(propagation = Propagation.MANDATORY)
public void addMandatory(String method) {
User2 user = new User2();
user.setName(method + "李四");
user2Repository.save(user);
}
@Transactional(propagation = Propagation.MANDATORY)
public void addMandatoryException(String method) {
User2 user = new User2();
user.setName(method + "王五");
user2Repository.save(user);
throw new RuntimeException();
}
}
| 序號 | 驗證方法 | USER1 | USER2 | 分析 |
|---|---|---|---|---|
| 1 | 外圍方法沒有事務(wù),調(diào)用有事務(wù)的方法1,調(diào)用有事務(wù)的方法2,外圍方法拋出異常 | 直接報錯 | No existing transaction found for transaction marked with propagation 'mandatory' | |
| 2 | 外圍方法沒有事務(wù), 調(diào)用有事務(wù)的方法1,調(diào)用有事務(wù)的方法2 ,方法2拋出異常 | 直接報錯 | No existing transaction found for transaction marked with propagation 'mandatory' | |
| 3 | 外圍方法有事務(wù), 調(diào)用有事務(wù)的方法1,調(diào)用有事務(wù)的方法2 ,外圍方法拋出異常 | 回滾 | 回滾 | 外圍有開啟事務(wù),調(diào)用的方法分別在獨立的自己的事務(wù)內(nèi),因為是MANDATORY,2個方法會加入已有的外圍創(chuàng)建的事務(wù),外圍方法的異常會導(dǎo)致方法1、方法2回滾 |
| 4 | 外圍方法有事務(wù), 調(diào)用有事務(wù)的方法1,調(diào)用有事務(wù)的方法2 ,方法2拋出異常 | 回滾 | 回滾 | 外圍有開啟事務(wù),調(diào)用的方法分別在獨立的自己的事務(wù)內(nèi),因為是MANDATORY,2個方法會加入已有的外圍創(chuàng)建的事務(wù),方法2的異常會導(dǎo)致方法1、方法2回滾 |
| 5 | 外圍方法有事務(wù), 調(diào)用有事務(wù)的方法1,調(diào)用有事務(wù)的方法2 ,方法2拋出異常,外圍方法捕獲異常 | 回滾 | 回滾 | 外圍有開啟事務(wù),調(diào)用的方法分別在獨立的自己的事務(wù)內(nèi),因為是required_new,都會加入到新的的事務(wù),所以方法1能成功,方法2拋出了異常就回滾了;由于捕獲了異常但是沒有拋出,會報錯: Transaction silently rolled back because it has been marked as rollback-only |
REQUIRES_NEW
不管當(dāng)前是否已經(jīng)存在事務(wù),都會新建一個事務(wù)
在外圍方法未開啟事務(wù)的情況下,Propagation.REQUIRES_NEW注解的內(nèi)部方法會新開啟自己的事務(wù),且開啟的事務(wù)相互獨立,互不干擾。
在外圍方法開啟事務(wù)的情況下,Propagation.REQUIRES_NEW注解的內(nèi)部方法依然會單獨開啟獨立事務(wù),且與外部方法事務(wù)也獨立,內(nèi)部方法之間、內(nèi)部方法和外部方法事務(wù)均相互獨立,互不干擾。
外圍方法調(diào)用方式與REQUIRED一致,只是內(nèi)部方法的注解改為了REQUIRES_NEW
@Service
public class RequiredNewUser1Service {
@Autowired
private User1Repository user1Repository;
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void addRequriedNew(String method) {
User1 user = new User1();
user.setName(method + "張三");
user1Repository.save(user);
}
}
@Service
public class RequiredNewUser2Service {
@Autowired
private User2Repository user2Repository;
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void addRequriedNew(String method) {
User2 user = new User2();
user.setName(method + "李四");
user2Repository.save(user);
}
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void addRequriedNewException(String method) {
User2 user = new User2();
user.setName(method + "王五");
user2Repository.save(user);
throw new RuntimeException();
}
}
| 序號 | 驗證方法 | USER1 | USER2 | 分析 |
|---|---|---|---|---|
| 1 | 外圍方法沒有事務(wù),調(diào)用有事務(wù)的方法1,調(diào)用有事務(wù)的方法2,外圍方法拋出異常 | 成功 | 成功 | 外圍沒有開啟事務(wù),調(diào)用的方法分別在獨立的自己的事務(wù)內(nèi),外圍方法拋出異常不會影響到調(diào)用方法的的事務(wù),所以都能成功 |
| 2 | 外圍方法沒有事務(wù), 調(diào)用有事務(wù)的方法1,調(diào)用有事務(wù)的方法2 ,方法2拋出異常 | 成功 | 回滾 | 外圍沒有開啟事務(wù),調(diào)用的方法分別在獨立的自己的事務(wù)內(nèi),方法2拋出異常只會回滾本身的事務(wù)。 |
| 3 | 外圍方法有事務(wù), 調(diào)用有事務(wù)的方法1,調(diào)用有事務(wù)的方法2 ,外圍方法拋出異常 | 成功 | 成功 | 外圍有開啟事務(wù),調(diào)用的方法分別在獨立的自己的事務(wù)內(nèi),因為是required_new,都會加入到新的的事務(wù),外圍方法的異常不會影響方法1、方法2,所以都能成功 |
| 4 | 外圍方法有事務(wù), 調(diào)用有事務(wù)的方法1,調(diào)用有事務(wù)的方法2 ,方法2拋出異常 | 成功 | 回滾 | 外圍有開啟事務(wù),調(diào)用的方法分別在獨立的自己的事務(wù)內(nèi),因為是required_new,都會加入到新的的事務(wù),所以方法1能成功,方法2拋出了異異常就回滾了 |
| 5 | 外圍方法有事務(wù), 調(diào)用有事務(wù)的方法1,調(diào)用有事務(wù)的方法2 ,方法2拋出異常,外圍方法捕獲異常 | 成功 | 回滾 | 外圍有開啟事務(wù),調(diào)用的方法分別在獨立的自己的事務(wù)內(nèi),因為是required_new,都會加入到新的的事務(wù),所以方法1能成功,方法2拋出了異常就回滾了;由于捕獲了異常但是沒有拋出,會報錯: Transaction silently rolled back because it has been marked as rollback-only |
NOT_SUPPORTED
當(dāng)前方法不應(yīng)該有事務(wù),如果有事務(wù)存在,將它掛起,以無事務(wù)狀態(tài)運行
不管外圍方法是否有事務(wù),NOT_SUPPORT都會以無事務(wù)的方式運行
外圍方法調(diào)用方式與REQUIRED一致,只是內(nèi)部方法的注解改為了NOT_SUPPORTED
@Service
public class NotSupportUser1Service {
@Autowired
private User1Repository user1Repository;
@Transactional(propagation = Propagation.NOT_SUPPORTED)
public void addNotSupport(String method) {
User1 user = new User1();
user.setName(method + "張三");
user1Repository.save(user);
}
}
@Service
public class NotSupportUser2Service {
@Autowired
private User2Repository user2Repository;
@Transactional(propagation = Propagation.NOT_SUPPORTED)
public void addNotSupport(String method) {
User2 user = new User2();
user.setName(method + "李四");
user2Repository.save(user);
}
@Transactional(propagation = Propagation.NOT_SUPPORTED)
public void addNotSupportException(String method) {
User2 user = new User2();
user.setName(method + "王五");
user2Repository.save(user);
throw new RuntimeException();
}
}
| 序號 | 驗證方法 | USER1 | USER2 | 分析 |
|---|---|---|---|---|
| 1 | 5個驗證方法 | 成功 | 成功 | 不管外圍方法是否有事務(wù),內(nèi)部的方法1,方法2都會以無事務(wù)的方式運行,所以拋出異常不會回滾 |
NEVER
注釋的業(yè)務(wù)方法絕對不能在事務(wù)中運行,否則拋出異常
在外圍方法未開啟事務(wù)的情況下,Propagation.NEVER注解的內(nèi)部方法會以無事務(wù)的方式運行。
在外圍方法開啟事務(wù)的情況下,Propagation.NEVER注解的內(nèi)部方法會因為不能加入到事務(wù)中,拋出異常Existing transaction found for transaction marked with propagation 'never'
@Service
public class NeverUser1Service {
@Autowired
private User1Repository user1Repository;
@Transactional(propagation = Propagation.NEVER)
public void addNever(String method) {
User1 user = new User1();
user.setName(method + "張三");
user1Repository.save(user);
}
}
@Service
public class NeverUser2Service {
@Autowired
private User2Repository user2Repository;
@Transactional(propagation = Propagation.NEVER)
public void addNever(String method) {
User2 user = new User2();
user.setName(method + "李四");
user2Repository.save(user);
}
@Transactional(propagation = Propagation.NEVER)
public void addNeverException(String method) {
User2 user = new User2();
user.setName(method + "王五");
user2Repository.save(user);
throw new RuntimeException();
}
}
| 序號 | 驗證方法 | USER1 | USER2 | 分析 |
|---|---|---|---|---|
| 1 | 外圍方法沒有事務(wù),調(diào)用有事務(wù)的方法1,調(diào)用有事務(wù)的方法2,外圍方法拋出異常 | 成功 | 成功 | 外圍沒有開啟事務(wù),調(diào)用的方法1,方法2都以無事務(wù)方式運行,外圍方法拋出異常不會回滾 |
| 2 | 外圍方法沒有事務(wù), 調(diào)用有事務(wù)的方法1,調(diào)用有事務(wù)的方法2 ,方法2拋出異常 | 成功 | 成功 | 外圍沒有開啟事務(wù),調(diào)用的方法1,方法2都以無事務(wù)方式運行,方法2拋出異常不會回滾 |
| 3,4,5 | 外圍方法有事務(wù), 調(diào)用有事務(wù)的方法1,調(diào)用有事務(wù)的方法2 | 拋出異常 | 外圍有開啟事務(wù),因為是NEVER,無法在已存在的事務(wù)中運行,會拋出和異常:Existing transaction found for transaction marked with propagation 'never' |
NESTED
在當(dāng)前事務(wù)上開啟一個子事務(wù)(Savepoint),如果提交主事務(wù)。那么連同子事務(wù)一同遞交。如果提交子事務(wù)則保存點之前的所有事務(wù)都會被遞交;如果當(dāng)前不存在事務(wù),就按REQUIRED方式
外圍方法沒有開啟事務(wù),Propagation.NESTED注解的內(nèi)部方法會新開啟自己的事務(wù),且開啟的事務(wù)相互獨立,互不干擾。
外圍方法開啟事務(wù),Propagation.NESTED注解的內(nèi)部方法會在已存在的事務(wù)中開啟一個子事務(wù),拋出子事務(wù)的方法拋出異??梢员煌鈬椒ú东@,不會影響主事務(wù);而外圍方法的主事務(wù)回滾卻會導(dǎo)致子事務(wù)也會回滾(與requried不同的是:nested的異常被捕獲了不會影響外層方法的事務(wù)。)。
@Service
public class NestedUser1Service {
@Autowired
private User1Repository user1Repository;
@Transactional(propagation = Propagation.NESTED)
public void addNested(String method) {
User1 user = new User1();
user.setName(method + "張三");
user1Repository.save(user);
}
}
@Service
public class NestedUser2Service {
@Autowired
private User2Repository user2Repository;
@Transactional(propagation = Propagation.NESTED)
public void addNested(String method) {
User2 user = new User2();
user.setName(method + "李四");
user2Repository.save(user);
}
@Transactional(propagation = Propagation.NESTED)
public void addNestedException(String method) {
User2 user = new User2();
user.setName(method + "王五");
user2Repository.save(user);
throw new RuntimeException();
}
}
如果按照上面的那種通過jpa的方式,當(dāng)外圍方法有事務(wù)的時候,運行會報錯:JpaDialect does not support savepoints - check your JPA provider's capabilities
意思是通過jpa的方式不支持savepoints,
所以需要通過JdbcTemplte的方式運行,
這里另起了一個項目,spring boot 集成jdbc來測試:
@Service
public class NestedUser1Service {
@Autowired
private JdbcTemplate jdbcTemplate;
@Transactional(propagation = Propagation.NESTED)
public void addNested(String method) {
String name = method + "張三";
jdbcTemplate.execute("insert into user1(name) values('" + name + "')");
}
}
@Service
public class NestedUser2Service {
@Autowired
private JdbcTemplate jdbcTemplate;
@Transactional(propagation = Propagation.NESTED)
public void addNested(String method) {
String name = method + "李四";
jdbcTemplate.execute("insert into user2(name) values('" + name + "')");
}
@Transactional(propagation = Propagation.NESTED)
public void addNestedException(String method) {
String name = method + "李四";
jdbcTemplate.execute("insert into user2(name) values('" + name + "')");
throw new RuntimeException();
}
}
增加一個插入USER3在外層方法上,來驗證回滾的范圍,同時在所有的sql運行之后加入一行日志打印,指示插入操作是否執(zhí)行了。
第一種方式:插入USER3在方法1方法2之后 (在最開頭REQUIRED中的5種調(diào)用方式都按這種方式加入USER3的保存方法)
@Autowired
private JdbcTemplate jdbcTemplate;
public void notransactionExceptionNotSupportNotSupport() {
user1Service.addNested(TYPE + 1);
user2Service.addNested(TYPE + 1);
String name = TYPE + "1王五";
jdbcTemplate.execute("insert into user3(name) values('" + name + "')");
System.out.println("USER3 插入執(zhí)行成功");
throw new RuntimeException();
}
| 序號 | 驗證方法 | user1 | user2 | USER3 | 分析 |
|---|---|---|---|---|---|
| 1 | 外圍方法沒有事務(wù),調(diào)用有事務(wù)的方法1,調(diào)用有事務(wù)的方法2,外圍方法拋出異常 | 成功 | 成功 | 成功 | 外圍沒有事務(wù),內(nèi)部按照REQUIRED運行 |
| 2 | 外圍方法沒有事務(wù), 調(diào)用有事務(wù)的方法1,調(diào)用有事務(wù)的方法2 ,方法2拋出異常 | 成功 | 回滾 | 拋出異常沒有運行 | 外圍沒有事務(wù),內(nèi)部按照REQUIRED運行;由于USER3是異常之后,沒有運行到。 |
| 3 | 外圍方法有事務(wù), 調(diào)用有事務(wù)的方法1,調(diào)用有事務(wù)的方法2 ,外圍方法拋出異常 | 回滾 | 回滾 | 回滾 | 外圍方法的異常會回滾nested注解的事務(wù) |
| 4 | 外圍方法有事務(wù), 調(diào)用有事務(wù)的方法1,調(diào)用有事務(wù)的方法2 ,方法2拋出異常 | 回滾 | 回滾 | 拋出異常沒有運行 | 方法2拋出異常回滾到該子事務(wù)設(shè)置的保存點,然后異常往上拋出到外層方法,所以導(dǎo)致方法1回滾了,由于USER3是異常之后執(zhí)行,沒有運行到。 |
| 5 | 外圍方法有事務(wù), 調(diào)用有事務(wù)的方法1,調(diào)用有事務(wù)的方法2 ,方法2拋出異常,外圍方法捕獲異常 | 成功 | 回滾 | 成功 | 方法2拋出異常只回滾到該子事務(wù)設(shè)置的保存點,然后異常拋出后被捕獲了,所以不會影響外層方法和方法1的結(jié)果 |
第二種方式:插入USER3在方法1方法2 之前 (在最開頭REQUIRED中的5種調(diào)用方式都按這種方式加入USER3的保存方法)
@Autowired
private JdbcTemplate jdbcTemplate;
public void notransactionExceptionNotSupportNotSupport() {
String name = TYPE + "1王五";
jdbcTemplate.execute("insert into user3(name) values('" + name + "')");
System.out.println("USER3 插入執(zhí)行成功");
user1Service.addNested(TYPE + 1);
user2Service.addNested(TYPE + 1);
throw new RuntimeException();
}
| 序號 | 驗證方法 | user1 | user2 | USER3 | 分析 |
|---|---|---|---|---|---|
| 1 | 外圍方法沒有事務(wù),調(diào)用有事務(wù)的方法1,調(diào)用有事務(wù)的方法2,外圍方法拋出異常 | 成功 | 成功 | 成功 | 外圍沒有事務(wù),內(nèi)部按照REQUIRED運行 |
| 2 | 外圍方法沒有事務(wù), 調(diào)用有事務(wù)的方法1,調(diào)用有事務(wù)的方法2 ,方法2拋出異常 | 成功 | 回滾 | 成功 | 外圍沒有事務(wù),內(nèi)部按照REQUIRED運行 |
| 3 | 外圍方法有事務(wù), 調(diào)用有事務(wù)的方法1,調(diào)用有事務(wù)的方法2 ,外圍方法拋出異常 | 回滾 | 回滾 | 回滾 | 外圍方法的異常會回滾nested注解的事務(wù) |
| 4 | 外圍方法有事務(wù), 調(diào)用有事務(wù)的方法1,調(diào)用有事務(wù)的方法2 ,方法2拋出異常 | 回滾 | 回滾 | 回滾 | 方法2拋出異?;貪L到該子事務(wù)設(shè)置的保存點,然后異常往上拋出到外層方法,所以導(dǎo)致外層方法和方法1都回滾了 |
| 5 | 外圍方法有事務(wù), 調(diào)用有事務(wù)的方法1,調(diào)用有事務(wù)的方法2 ,方法2拋出異常,外圍方法捕獲異常 | 成功 | 回滾 | 成功 | 方法2拋出異常只回滾到該子事務(wù)設(shè)置的保存點,然后異常拋出后被捕獲了,所以不會影響外層方法和方法1的結(jié)果 |