事务传播行为
參考:https://segmentfault.com/a/1190000013341344
例子:
準(zhǔn)備 對(duì)日志log表的service層操作
package com.wing.my.cloud.system.modular.system.service;
import com.wing.my.cloud.system.modular.system.definedLog.entity.DefineLogEntity;
import com.wing.my.cloud.system.modular.system.mapper.DefineLogMapper;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import javax.annotation.Resource;
/**
* <p>
* 測(cè)試事務(wù)A
* </p>
*
*/
@Service
public class Transaction1Service {
@Resource
DefineLogMapper defineLogMapper;
@Transactional(propagation = Propagation.REQUIRED)
public void addLog_Required(){
DefineLogEntity defineLogEntity = new DefineLogEntity();
defineLogEntity.setClassName("Transaction1Service");
defineLogEntity.setMethodName("addLogRequired");
defineLogMapper.insert(defineLogEntity);
}
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void addLog_REQUIRES_NEW(){
DefineLogEntity defineLogEntity = new DefineLogEntity();
defineLogEntity.setClassName("Transaction1Service");
defineLogEntity.setMethodName("addLogREQUIRES_NEW");
defineLogMapper.insert(defineLogEntity);
}
@Transactional(propagation = Propagation.NESTED)
public void addLog_NESTED(){
DefineLogEntity defineLogEntity = new DefineLogEntity();
defineLogEntity.setClassName("Transaction1Service");
defineLogEntity.setMethodName("addLogNESTED");
defineLogMapper.insert(defineLogEntity);
}
}
View Code
對(duì)user表的service層的操作
package com.wing.my.cloud.system.modular.system.service;
import com.wing.my.cloud.system.modular.system.entity.User;
import com.wing.my.cloud.system.modular.system.mapper.UserMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import javax.annotation.Resource;
/**
* <p>
* 測(cè)試事務(wù)B
* </p>
*
*/
@Service
@Slf4j
public class Transaction2Service {
@Resource
UserMapper userMapper;
@Transactional(propagation = Propagation.REQUIRED)
public void addUser_REQUIRED(){
User user = User.builder()
.account("張三REQUIRED")
.status("ENABLE")
.build();
userMapper.insert(user);
}
@Transactional(propagation = Propagation.REQUIRED)
public void addUser_REQUIRED_RuntimeException(){
User user = User.builder()
.account("張三REQUIRED運(yùn)行時(shí)異常").status("ENABLE").build();
userMapper.insert(user);
throw new RuntimeException("RuntimeException是運(yùn)行時(shí)異常,事務(wù)自動(dòng)回滾");
}
/**
* 因?yàn)楫惓1怀缘?所以走不成事務(wù),不會(huì)回滾
*/
@Transactional(propagation = Propagation.REQUIRED)
public void addUser_REQUIRED_RuntimeException_Try(){
User user = User.builder()
.account("張三REQUIRED運(yùn)行時(shí)異常被cacth掉").status("ENABLE").build();
userMapper.insert(user);
try {
throw new RuntimeException("RuntimeException是運(yùn)行時(shí)異常,事務(wù)自動(dòng)回滾");
} catch (Exception e) {
log.error("異常被吃掉");
}
}
@Transactional(noRollbackFor = RuntimeException.class,propagation = Propagation.REQUIRED)
public void addUser_REQUIRED_RuntimeException_NoRollbackFor(){
User user = User.builder()
.account("張三REQUIRED運(yùn)行時(shí)異常").status("ENABLE").build();
userMapper.insert(user);
throw new RuntimeException("加上noRollbackFor也不會(huì)走事務(wù)。");
}
@Transactional(propagation = Propagation.REQUIRED)
public void addUser_REQUIRED_Exception() throws Exception{
User user = User.builder()
.account("張三REQUIRED非運(yùn)行時(shí)異常").status("ENABLE").build();
userMapper.insert(user);
throw new Exception("Exception是非運(yùn)行時(shí)異常,事務(wù)失效");
}
@Transactional(rollbackFor = Exception.class,propagation = Propagation.REQUIRED)
public void addUser_REQUIRED_Exception_RollbackFor() throws Exception{
User user = User.builder()
.account("張三REQUIRED非運(yùn)行時(shí)異常").status("ENABLE").build();
userMapper.insert(user);
throw new Exception("Exception是非運(yùn)行時(shí)異常,事務(wù)失效");
}
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void addUser_REQUIRES_NEW(){
User user = User.builder()
.account("李四REQUIRES_NEW")
.status("ENABLE")
.build();
userMapper.insert(user);
}
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void addUser_REQUIRES_NEW_Exception(){
User user = User.builder()
.account("李四REQUIRES_NEW運(yùn)行時(shí)異常").build();
userMapper.insert(user);
throw new RuntimeException("RuntimeException是運(yùn)行時(shí)異常,事務(wù)自動(dòng)回滾");
}
@Transactional(propagation = Propagation.NESTED)
public void addUser_NESTED(){
User user = User.builder()
.account("李四NESTED")
.status("ENABLE")
.build();
userMapper.insert(user);
}
@Transactional(propagation = Propagation.NESTED)
public void addUser_NESTED_Exception(){
User user = User.builder()
.account("李四NESTED運(yùn)行時(shí)異常").status("ENABLE").build();
userMapper.insert(user);
throw new RuntimeException("RuntimeException是運(yùn)行時(shí)異常,事務(wù)自動(dòng)回滾");
}
}
View Code
對(duì)事務(wù)的操作
package com.wing.my.cloud.system.modular.system.service;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import javax.annotation.Resource;
/**
* <p>
* 事務(wù)嵌套
* </p>
*
*/
@Service
@Slf4j
public class Transaction3Service {
@Resource
Transaction1Service transaction1Service;
@Resource
Transaction2Service transaction2Service;
/**
* log添加一條數(shù)據(jù)
* user添加一條數(shù)據(jù)
* @throws Exception
*/
public void exception失效() throws Exception{
transaction1Service.addLog_Required();
transaction2Service.addUser_REQUIRED_Exception();
log.info("只有在返回的是不受檢查異常才會(huì)有效,exception是檢查異常。不會(huì)走事務(wù)");
}
/**
* log添加一條數(shù)據(jù)
* @throws Exception
*/
public void exception失效但是事務(wù)_加上rollbackFor可以走事務(wù)() throws Exception{
transaction1Service.addLog_Required();
transaction2Service.addUser_REQUIRED_Exception_RollbackFor();
log.info("Exception加上rollbackFor會(huì)走事務(wù)");
}
/**
* log添加一條數(shù)據(jù)
*/
public void RuntimeException可以走事務(wù)(){
transaction1Service.addLog_Required();
transaction2Service.addUser_REQUIRED_RuntimeException();
log.info("只有在返回的是不受檢查異常才會(huì)有效,RuntimeException是非檢查異常。會(huì)走事務(wù)");
}
/**
* log添加一條數(shù)據(jù)
* user添加一條數(shù)據(jù)
*/
public void RuntimeException可以走事務(wù)_加上noRollbackFor不會(huì)走事務(wù)(){
transaction1Service.addLog_Required();
transaction2Service.addUser_REQUIRED_RuntimeException_NoRollbackFor();
log.info("noRollbackFor不會(huì)走事務(wù)");
}
public void 異常被吃掉(){
transaction2Service.addUser_REQUIRED_RuntimeException_Try();
}
/**
* REQUIRED
* 如果當(dāng)前沒有事務(wù),就新建一個(gè)事務(wù)。已經(jīng)存在事務(wù),就加入到這個(gè)事務(wù)中
* 外層沒有事務(wù),內(nèi)層Log,內(nèi)層User有事務(wù)。
* 內(nèi)層事務(wù)沒有異常。外層有異常。
* 外層回滾,內(nèi)層不會(huì)回滾。內(nèi)層的事務(wù)是單獨(dú)運(yùn)行的。
*
* log添加一條數(shù)據(jù)
* user添加一條數(shù)據(jù)
*/
public void REQUIRED_外層無事務(wù)_兩個(gè)內(nèi)層事務(wù)獨(dú)立_都無異常(){
transaction1Service.addLog_Required();
transaction2Service.addUser_REQUIRED();
log.info("兩個(gè)事務(wù)" +
"外層沒有事務(wù),內(nèi)層有事務(wù).內(nèi)層都沒有異常。外層有異常。外層回滾,內(nèi)層不會(huì)回滾。因?yàn)椴辉谝粋€(gè)事務(wù)中");
throw new RuntimeException();
}
/**
* log添加一條數(shù)據(jù)
*/
public void REQUIRED_外層無事務(wù)_兩個(gè)內(nèi)層事務(wù)獨(dú)立_USER有異常(){
transaction1Service.addLog_Required();
transaction2Service.addUser_REQUIRED_RuntimeException();
log.info("兩個(gè)事務(wù)" +
"外層沒有事務(wù),內(nèi)層有事務(wù).內(nèi)層事務(wù)User有異常。外層有異常。外層回滾,內(nèi)層Log沒有異常,不會(huì)回滾。內(nèi)層User有異常,回滾.因?yàn)椴辉谝粋€(gè)事務(wù)中");
throw new RuntimeException();
}
//-----外層不開事務(wù)。REQUIRED修飾的內(nèi)層事務(wù)會(huì)新開自己的事務(wù)?;ハ嗒?dú)立,互不干擾。
/**
* 都不添加數(shù)據(jù)
*/
@Transactional(propagation = Propagation.REQUIRED)
public void REQUIRED_外層有事務(wù)_兩個(gè)內(nèi)層事務(wù)加入到外層事務(wù)() {
transaction1Service.addLog_Required();
transaction2Service.addUser_REQUIRED();
log.info("一個(gè)事務(wù)" +
"外層有事務(wù),內(nèi)層兩個(gè)都有事務(wù),都沒有異常.事務(wù)Log和事務(wù)User都加入到外層的事務(wù)中。外層回滾,內(nèi)層也回滾");
throw new RuntimeException();
}
/**
* 都不添加數(shù)據(jù)
*/
@Transactional(propagation = Propagation.REQUIRED)
public void REQUIRED_外層有事務(wù)_兩個(gè)內(nèi)層事務(wù)加入到外層事務(wù)_事務(wù)USER有異常_外層感知到(){
transaction1Service.addLog_Required();
transaction2Service.addUser_REQUIRED_RuntimeException();
log.info("一個(gè)事務(wù)" +
"外層有事務(wù),內(nèi)層加入外層事務(wù)。內(nèi)層拋出異?;貪L,外層感知到異常使整個(gè)事務(wù)都回滾");
throw new RuntimeException();
}
/**
* 都不添加數(shù)據(jù)
*/
@Transactional(propagation = Propagation.REQUIRED)
public void REQUIRED_外層有事務(wù)_兩個(gè)內(nèi)層事務(wù)加入到外層事務(wù)_外層有異常_事務(wù)USER有異常_被catch吃掉_外層感知不到(){
transaction1Service.addLog_Required();
try {
transaction2Service.addUser_REQUIRED_RuntimeException();
} catch (Exception e) {
log.error("一共一個(gè)事務(wù)" +
"內(nèi)層事務(wù)的異常被吃掉,外層感知不到異常。但是本身外層有異常,外層回滾。內(nèi)層也回滾");
}
throw new RuntimeException();
}
//-----外層開啟事務(wù)。REQUIRED修飾的內(nèi)層事務(wù)會(huì)加入到外層事務(wù)中。所有的事務(wù)都在同一個(gè)事務(wù)中了。只要有一個(gè)方法回滾。所有的都回滾
/**
* 都不添加數(shù)據(jù)
*/
@Transactional(propagation = Propagation.REQUIRED)
public void REQUIRED_外層有事務(wù)_兩個(gè)內(nèi)層事務(wù)加入到外層事務(wù)_事務(wù)USER有異常_被catch吃掉_外層感知不到(){
transaction1Service.addLog_Required();
try {
transaction2Service.addUser_REQUIRED_RuntimeException();
} catch (Exception e) {
log.error("一共一個(gè)事務(wù)" +
"內(nèi)層事務(wù)的異常被吃掉,外層感知不到異常。但是當(dāng)前事務(wù)已經(jīng)被標(biāo)記為rollbackOnly了,所以無法提交");
}
}
//-----外層開啟事務(wù)后,內(nèi)層事務(wù)加入到外層事務(wù)。內(nèi)層方法拋出異?;貪L,即使被trycatch吃掉。不被外層方法感知到。整個(gè)事務(wù)依舊回滾。
// ------因?yàn)樵谕粋€(gè)事務(wù)中,只要有異常,都會(huì)被察覺到。然后執(zhí)行回滾。
/**
* REQUIRES_NEW
* 新建事務(wù),如果當(dāng)前存在事務(wù),就把當(dāng)前事務(wù)掛起
*
* 外層沒有事務(wù),兩個(gè)內(nèi)層都是在自己的事務(wù)中 。外層拋出異?;貪L不會(huì)影響內(nèi)層的方法。
* log插入一條數(shù)據(jù)
* user插入一條數(shù)據(jù)
*/
public void REQUIRES_NEW_兩個(gè)內(nèi)層事務(wù)獨(dú)立(){
transaction1Service.addLog_REQUIRES_NEW();
transaction2Service.addUser_REQUIRES_NEW();
log.info("一共兩個(gè)事務(wù)" +
"外層沒有事務(wù),內(nèi)層有事務(wù)。兩個(gè)內(nèi)層都沒有異常。外層有異常。外層回滾,內(nèi)層不會(huì)有回滾");
throw new RuntimeException();
}
/**
* log插入一條數(shù)據(jù)
*/
public void REQUIRES_NEW_兩個(gè)內(nèi)層事務(wù)獨(dú)立_USER有異常_不會(huì)影響LOG事務(wù)() {
transaction1Service.addLog_REQUIRES_NEW();
transaction2Service.addUser_REQUIRES_NEW_Exception();
log.info("一共兩個(gè)事務(wù)。" +
"外層沒有事務(wù),內(nèi)層兩個(gè)都有事務(wù),logRequires_new事務(wù)沒有異常,插入成功" +
"userRequires_new有異常,回滾");
throw new RuntimeException();
}
//外層未開啟事務(wù)的情況下,REQUIRES_NEW修飾的內(nèi)層事務(wù) 新開自己的事務(wù)?;ハ嗒?dú)立。互不干擾。
/**
* log_requires_new插入一條
* user_requires_new插入一條
*/
@Transactional(propagation = Propagation.REQUIRED)
public void REQUIRES_NEW_內(nèi)層事務(wù)獨(dú)立存在不加入到外層事務(wù)中(){
transaction1Service.addLog_Required();
transaction1Service.addLog_REQUIRES_NEW();
transaction2Service.addUser_REQUIRES_NEW();
log.info("一共3個(gè)事務(wù)。" +
"logRequired會(huì)加入到外層的事務(wù)中。logRequires_new和userRequires_new都是單獨(dú)的事務(wù)。外層事務(wù)有異常,回滾。不會(huì)插入數(shù)據(jù)。" +
"兩個(gè)requires_new都是單獨(dú)的事務(wù),沒有異常,插入成功。");
throw new RuntimeException();
}
/**
* log_requires_new插入一條數(shù)據(jù)
*/
@Transactional(propagation = Propagation.REQUIRED)
public void REQUIRES_NEW_內(nèi)層事務(wù)獨(dú)立不會(huì)加入到外層事務(wù)中_USER事務(wù)有異常不會(huì)影響到外層和log事務(wù)(){
transaction1Service.addLog_Required();
transaction1Service.addLog_REQUIRES_NEW();
transaction2Service.addUser_REQUIRES_NEW_Exception();
log.info("一共三個(gè)事務(wù)" +
"logRequired會(huì)加入到外層的事務(wù)中。userRequiresNew返回異常,外層捕獲到異常。logRequired回滾" +
"logrequires_new是單獨(dú)的事務(wù),沒有異常,插入成功。" +
"userRequires_new是單獨(dú)的事務(wù),有異常,回滾。");
}
/**
* logRequired插入成功
* logRequires_new插入成功
*/
@Transactional(propagation = Propagation.REQUIRED)
public void REQUIRES_NEW_內(nèi)層事務(wù)獨(dú)立_內(nèi)層USER事務(wù)被吃掉(){
transaction1Service.addLog_Required();
transaction1Service.addLog_REQUIRES_NEW();
try {
transaction2Service.addUser_REQUIRES_NEW_Exception();
} catch (Exception e) {
log.error("一共有三個(gè)事務(wù)。" +
"內(nèi)層logRequired加入到外層事務(wù)中。因?yàn)閡serRequires_new返回的異常被吃掉。外層感知不到異常。沒有回滾。插入成功" +
"內(nèi)層userRequires_new是單獨(dú)的事務(wù)。沒有異常,插入成功" +
"內(nèi)層userRequires_newException是單獨(dú)的事務(wù),有異常,進(jìn)行回滾。不會(huì)插入成功");
}
}
/**
* logRequires_new插入成功
* userRequires_new插入成功
*/
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void REQUIRES_NEW新開事務(wù)_REQUIRED加入外層事務(wù)(){
transaction1Service.addLog_Required();
transaction1Service.addLog_REQUIRES_NEW();
transaction2Service.addUser_REQUIRES_NEW();
log.info("一共3個(gè)事務(wù)。" +
"外層一個(gè)。logRequired加入到外層事務(wù)。logRequires_new新創(chuàng)建一個(gè)事務(wù).userRequires_new新創(chuàng)建一個(gè)事務(wù)" +
"3個(gè)內(nèi)層事務(wù)沒有異常。但是logRequired加入到外層事務(wù)中了,外層事務(wù)有異常,不會(huì)插入成功。另外兩個(gè)內(nèi)層事務(wù)插入成功。" );
throw new RuntimeException();
}
//-----外層開啟事務(wù)。內(nèi)層用REQUIRES_NEW修飾的方法依舊會(huì)開啟獨(dú)立事務(wù)。且與外層事務(wù)也獨(dú)立,互相獨(dú)立,互不干擾。
/**
* 不添加
*/
@Transactional(propagation = Propagation.REQUIRED)
public void NESTED_內(nèi)層事務(wù)是外層的子事務(wù)_外層有異常外層回滾_兩個(gè)子事務(wù)都回滾(){
transaction1Service.addLog_NESTED();
transaction2Service.addUser_NESTED();
log.info("兩個(gè)事務(wù)。" +
"logNested是外部事務(wù)的子事務(wù)" +
"userNested是外部事務(wù)的子事務(wù)" +
"外層事務(wù)有異常,回滾。兩個(gè)子事務(wù)都回滾");
throw new RuntimeException();
}
/**
* 不添加
*/
@Transactional(propagation = Propagation.REQUIRED)
public void NESTED_內(nèi)層事務(wù)是外層事務(wù)的子事務(wù)_子事務(wù)有異常被外層感知到所有子事務(wù)都回滾(){
transaction1Service.addLog_NESTED();
transaction2Service.addUser_NESTED_Exception();
log.info("兩個(gè)事務(wù)。" +
"logNested是外部事務(wù)的子事務(wù)" +
"userNested是外部事務(wù)的子事務(wù)" +
"userNested有異常,外層感知到異常。外層回滾,兩個(gè)子事務(wù)都回滾" );
}
/**
* log_nested添加成功
*/
@Transactional(propagation = Propagation.REQUIRED)
public void NESTED_內(nèi)層方法是外層事務(wù)的子事務(wù)_子事務(wù)異常不被外層感知到有異常的子事務(wù)回滾_沒有異常的子事務(wù)提交(){
transaction1Service.addLog_NESTED();
try {
transaction2Service.addUser_NESTED_Exception();
} catch (Exception e) {
log.error("兩個(gè)事務(wù)。" +
"logNested是外部事務(wù)的子事務(wù)" +
"userNested是外部事務(wù)的子事務(wù)" +
"userNested有異常,但是被catch捕獲到。外層感知不到異常。userNested回滾" +
"logNested沒有異常。提交");
}
}
//------NESTED修飾的內(nèi)層方法是外部事務(wù)的子事務(wù),外層回滾。內(nèi)層的都回滾。內(nèi)層的獨(dú)立存在,互不干擾
//--------外層沒有事務(wù)的時(shí)候。也是新開事務(wù),互相獨(dú)立。互不干擾。
/**
* userRequires_new插入成功
*/
@Transactional(propagation = Propagation.REQUIRED)
public void 組合(){
transaction1Service.addLog_Required();
transaction2Service.addUser_REQUIRES_NEW();
transaction2Service.addUser_NESTED();
transaction2Service.addUser_NESTED_Exception();
log.info("兩個(gè)事務(wù)" +
"logRequired加入到外層事務(wù),外層捕獲到userNested返回的異常,回滾" +
"userRequires_new新開事務(wù)。與外層沒有影響" +
"userNested和userNestedException都是外層的子事務(wù),外層捕獲到異常,進(jìn)行回滾,兩個(gè)子事務(wù)也進(jìn)行回滾");
}
}
View Code
總結(jié):
一:分析事務(wù)
看外層。如果外層沒有事務(wù)。那么去分析包含的方法中有沒有加上事務(wù),有幾個(gè)方法加上了事務(wù)就開啟了幾個(gè)事務(wù)。這幾個(gè)事務(wù)是互相獨(dú)立,互不干擾的。
如果有事務(wù)。子事務(wù)中用REQUIRED 修飾的會(huì)加入到外層事務(wù)中。
子事務(wù)用REQUIRES_NEW 修飾的不會(huì)去搭理外層的事務(wù)。自己新開事務(wù)。
子事務(wù)用NESTED 修飾的是外層的子事務(wù)。如果外層事務(wù)回滾。外層事務(wù)下是所有子事務(wù)也回滾。
二:分析事務(wù)是否失效
2.1:拋出的是非運(yùn)行時(shí)異常。
比如拋出Exception
但是可以加上rollbackFor
@Transactional(rollbackFor = Exception.class,propagation = Propagation.REQUIRED)
拋出RunTimeException??梢宰呤聞?wù),如果不想走事務(wù)的話可以加上noRollbackFor
@Transactional(noRollbackFor = RuntimeException.class,propagation = Propagation.REQUIRED)
2.2:異常被catch掉
/**
* 因?yàn)楫惓1怀缘?所以走不成事務(wù),不會(huì)回滾
*/
@Transactional(propagation = Propagation.REQUIRED)
public void addUser_REQUIRED_RuntimeException_Try(){
User user = User.builder()
.account("張三REQUIRED運(yùn)行時(shí)異常被cacth掉").status("ENABLE").build();
userMapper.insert(user);
try {
throw new RuntimeException("RuntimeException是運(yùn)行時(shí)異常,事務(wù)自動(dòng)回滾");
} catch (Exception e) {
log.error("異常被吃掉");
}
}
public void 異常被吃掉(){
transaction2Service.addUser_REQUIRED_RuntimeException_Try();
}
異常被吃掉解決方案。
@Transactional(propagation = Propagation.REQUIRED)
public void addUser_REQUIRED_RuntimeException_Try(){
User user = User.builder()
.account("張三REQUIRED運(yùn)行時(shí)異常被cacth掉").status("ENABLE").build();
userMapper.insert(user);
try {
throw new RuntimeException("RuntimeException是運(yùn)行時(shí)異常,事務(wù)自動(dòng)回滾");
} catch (Exception e) {
log.error("異常被吃掉");
//解決方案一:在catch中加上 throw new RuntimeException() 把異常給拋出去。
//throw new RuntimeException();
//解決方案二: 在catch中手動(dòng)回滾
//TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
}
}
2.3:事務(wù)要用public修飾。
總結(jié)
- 上一篇: 使用WordPress的Kyma plu
- 下一篇: WordPress的Kyma plugi