Spring-Tx
传播行为
propagation | 提交 | 异常 | 捕获 | 后异常 |
---|
required (rollbackOnly) | do nothing / commit | setRollbackOnly / rollback | setRollbackOnly / rollback | |
required_new (isNewTransaction) | commit / commit | rollback / rollback | rollback / commit | commit / rollback |
nested (savePoint) | releaseSavepoint / commit | rollbackToSavepoint & releaseSavepoint / rollback | rollbackToSavepoint & releaseSavePoint / commit | |
REQUIRED
如果当前没有事务,就新建一个事务,如果已经存在一个事务中,加入到这个事务中。
本质上是同一个事务
提交:什么也不做
异常传递:rollbackOnly = true
异常捕获:rollbackOnly = true
REQUIRED_NEW
新建事务,如果当前存在事务,把当前事务挂起。
提交:isNewTx = true 提交
异常传递:rollback / rollback
异常捕获:rollback / commit
异常后捕:commit / rollback
NESTED
如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则执行与PROPAGATION_REQUIRED类似的操作。
提交:releaseSavepoint / commit
异常传递:rollbackToSavepoint & releaseSavepoint / rollback
异常捕获:rollbackToSavepoint & releaseSavepoint / commit
SUPPORTS
支持当前事务,如果当前没有事务,就以非事务方式执行。
提交:
异常捕获:
异常传递:
MANDATORY
使用当前的事务,如果当前没有事务,就抛出异常。
提交:
异常捕获:
异常传递:
NOT_SUPPORTS
以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。
提交:
异常捕获:
异常传递:
NEVER
以非事务方式执行,如果当前存在事务,则抛出异常。
提交:
异常捕获:
异常传递:
核心代码-AOP
TransactionInfo txInfo = createTransactionIfNecessary(tm,txAttr,joinpointIdentification);
Object retVal = null;
try {
retVal=invocation.proceedWithInvocation();
} catch(Throwable ex){
completeTransactionAfterThrowing(txInfo,ex);
throw ex;
} finally {
cleanupTransactionInfo(txInfo);
}
commitTransactionAfterReturning(txInfo);
return retVal;
回滚事务
if (status.hasSavepoint()) {
if (status.isDebug()) {
logger.debug("Rolling back transaction to savepoint");
}
status.rollbackToHeldSavepoint();
}
else if (status.isNewTransaction()) {
if (status.isDebug()) {
logger.debug("Initiating transaction rollback");
}
doRollback(status);
}
else if (status.hasTransaction()) {
if (status.isLocalRollbackOnly() || isGlobalRollbackOnParticipationFailure()) {
if (status.isDebug()) {
logger.debug("Participating transaction failed - marking existing transaction as rollback-only");
}
doSetRollbackOnly(status);
}
else {
if (status.isDebug()) {
logger.debug("Participating transaction failed - letting transaction originator decide on rollback");
}
}
}
提交事务-01
DefaultTransactionStatus defStatus = (DefaultTransactionStatus) status;
if (defStatus.isLocalRollbackOnly()) {
if (defStatus.isDebug()) {
logger.debug("Transactional code has requested rollback");
}
processRollback(defStatus);
return;
}
if (!shouldCommitOnGlobalRollbackOnly() && defStatus.isGlobalRollbackOnly()) {
if (defStatus.isDebug()) {
logger.debug("Global transaction is marked as rollback-only but transactional code requested commit");
}
processRollback(defStatus);
if (status.isNewTransaction() || isFailEarlyOnGlobalRollbackOnly()) {
throw new UnexpectedRollbackException("Transaction rolled back because it has been marked as rollback-only");
}
return;
}
processCommit(defStatus);
提交事务-02
if (status.isNewTransaction() || isFailEarlyOnGlobalRollbackOnly()) {
globalRollbackOnly = status.isGlobalRollbackOnly();
}
if (status.hasSavepoint()) {
if (status.isDebug()) {
logger.debug("Releasing transaction savepoint");
}
status.releaseHeldSavepoint();
}
else if (status.isNewTransaction()) {
if (status.isDebug()) {
logger.debug("Initiating transaction commit");
}
doCommit(status);
}
测试代码
package center.leon.springtx;
import center.leon.springtx.service.TxAService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.aop.framework.autoproxy.InfrastructureAdvisorAutoProxyCreator;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.transaction.annotation.AnnotationTransactionAttributeSource;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import org.springframework.transaction.event.TransactionalEventListenerFactory;
import org.springframework.transaction.interceptor.BeanFactoryTransactionAttributeSourceAdvisor;
import org.springframework.transaction.interceptor.TransactionInterceptor;
@Slf4j
@EnableTransactionManagement
@SpringBootApplication
public class SpringTxApplication {
public static void main(String[] args) {
ConfigurableApplicationContext run = SpringApplication.run(SpringTxApplication.class, args);
final InfrastructureAdvisorAutoProxyCreator infrastructureAdvisorAutoProxyCreator = run.getBean(InfrastructureAdvisorAutoProxyCreator.class);
assert null != infrastructureAdvisorAutoProxyCreator;
final TransactionalEventListenerFactory transactionalEventListenerFactory = run.getBean(TransactionalEventListenerFactory.class);
assert null != transactionalEventListenerFactory;
final AnnotationTransactionAttributeSource annotationTransactionAttributeSource = run.getBean(AnnotationTransactionAttributeSource.class);
assert null != annotationTransactionAttributeSource;
final TransactionInterceptor transactionInterceptor = run.getBean(TransactionInterceptor.class);
assert null != transactionInterceptor;
final BeanFactoryTransactionAttributeSourceAdvisor beanFactoryTransactionAttributeSourceAdvisor = run.getBean(BeanFactoryTransactionAttributeSourceAdvisor.class);
assert null != beanFactoryTransactionAttributeSourceAdvisor;
final TxAService txAService = run.getBean(TxAService.class);
txAService.truncateTable();
txAService.required_commit_NoTx_commit();
try {
txAService.required_commit_NoTx_Ex();
} catch (Exception e) {
}
txAService.required_commit_Required_commit();
try {
txAService.required_commit_Required_Ex();
} catch (Exception e) {
}
try {
txAService.required_commit_Required_Ex_Caught();
} catch (Exception e) {
}
txAService.required_commit_Required_New_Commit();
try {
txAService.required_commit_Required_New_Ex();
} catch (Exception e) {
}
txAService.required_commit_Required_New_Ex_Caught();
try {
txAService.required_Ex_Required_New_commit();
} catch (Exception e) {
}
txAService.required_commit_Required_Nested_Commit();
try {
txAService.required_commit_Required_Nested_Ex();
} catch (Exception e) {
}
txAService.required_commit_Required_Nested_Ex_Caught();
txAService.required_commit_or_ex_catch_This_Any_propagation_commit_or_ex_or_caught_is_invalid();
txAService.required_commit_or_ex_catch_Spring_Any_propagation_commit_or_ex_or_caught_invalid();
System.out.println("天地英雄气,千秋尚凛然");
}
}
ServiceA Interface
package center.leon.springtx.service;
public interface TxAService {
void truncateTable();
void required_commit_NoTx_commit();
void required_commit_NoTx_Ex();
void required_commit_Required_commit();
void required_commit_Required_Ex();
void required_commit_Required_Ex_Caught();
void required_commit_Required_New_Commit();
void required_commit_Required_New_Ex();
void required_commit_Required_New_Ex_Caught();
void required_Ex_Required_New_commit();
void required_commit_Required_Nested_Commit();
void required_commit_Required_Nested_Ex();
void required_commit_Required_Nested_Ex_Caught();
void required_commit_or_ex_catch_This_Any_propagation_commit_or_ex_or_caught_is_invalid();
void required_commit_or_ex_catch_This_Any_propagation_commit_or_ex_or_caught_is_invalid_this(String name);
void required_commit_or_ex_catch_Spring_Any_propagation_commit_or_ex_or_caught_invalid();
void required_commit_or_ex_catch_Spring_Any_propagation_commit_or_ex_or_caught_invalid_Spring(String name);
}
ServiceAImpl Class
package center.leon.springtx.service.impl;
import center.leon.springtx.dao.MonkeyDao;
import center.leon.springtx.mapper.MonkeyMapper;
import center.leon.springtx.service.TxAService;
import center.leon.springtx.service.TxBService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
@Service
@Slf4j
public class TxAServiceImpl implements TxAService {
@Autowired
private TxBService txBService;
@Autowired
private MonkeyDao monkeyDao;
@Autowired
private MonkeyMapper monkeyMapper;
@Autowired
private TxAService txAService;
@Override
public void truncateTable() {
monkeyMapper.truncateTable();
}
@Override
@Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
public void required_commit_NoTx_commit() {
monkeyDao.insert("required_commit_NoTx_commit_A");
txBService.required_commit_NoTx_commit("required_commit_NoTx_commit_B");
}
@Override
@Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
public void required_commit_NoTx_Ex() {
monkeyDao.insert("required_commit_NoTx_Ex_A");
txBService.required_commit_NoTx_Ex("required_commit_NoTx_Ex_B");
}
@Override
@Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
public void required_commit_Required_commit() {
monkeyDao.insert("required_commit_Required_commit_A");
txBService.required_commit_Required_commit("required_commit_Required_commit_B");
}
@Override
@Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
public void required_commit_Required_Ex() {
monkeyDao.insert("required_commit_Required_Ex_A");
txBService.required_commit_Required_Ex("required_commit_Required_Ex_B");
}
@Override
@Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
public void required_commit_Required_Ex_Caught() {
monkeyDao.insert("required_commit_Required_Ex_Caught_A");
try {
txBService.required_commit_Required_Ex_Caught("required_commit_Required_Ex_Caught_B");
} catch (Exception e) {
log.info("required_commit_Required_Ex_Caught_B. error : {}", e.getMessage(), e);
}
}
@Override
@Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
public void required_commit_Required_New_Commit() {
monkeyDao.insert("required_commit_Required_New_Commit_A");
txBService.required_commit_Required_New_Commit("required_commit_Required_New_Commit_B");
}
@Override
@Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
public void required_commit_Required_New_Ex() {
monkeyDao.insert("required_commit_Required_New_Ex_A");
txBService.required_commit_Required_New_Ex("required_commit_Required_New_Ex_B");
}
@Override
@Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
public void required_commit_Required_New_Ex_Caught() {
monkeyDao.insert("required_commit_Required_New_Ex_Caught_A");
try {
txBService.required_commit_Required_New_Ex_Caught("required_commit_Required_New_Ex_Caught_B");
} catch (Exception e) {
log.info("required_commit_Required_New_Ex_Caught_B : {}", e.getMessage(), e);
}
}
@Override
@Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
public void required_Ex_Required_New_commit() {
monkeyDao.insert("required_Ex_Required_New_commit_A");
txBService.required_Ex_Required_New_commit("required_Ex_Required_New_commit_B");
int i = 0 / 0;
}
@Override
@Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
public void required_commit_Required_Nested_Commit() {
monkeyDao.insert("required_commit_Required_Nested_Commit_A");
txBService.required_commit_Required_Nested_Commit("required_commit_Required_Nested_Commit_B");
}
@Override
@Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
public void required_commit_Required_Nested_Ex() {
monkeyDao.insert("required_commit_Required_Nested_Ex_A");
txBService.required_commit_Required_Nested_Ex("required_commit_Required_Nested_Ex_B");
}
@Override
@Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
public void required_commit_Required_Nested_Ex_Caught() {
monkeyDao.insert("required_commit_Required_Nested_Ex_Caught_A");
try {
txBService.required_commit_Required_Nested_Ex_Caught("required_commit_Required_Nested_Ex_Caught_B");
} catch (Exception e) {
log.info("required_commit_Required_Nested_Ex_Caught_B. error : {}", e.getMessage(), e);
}
}
@Override
@Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
public void required_commit_or_ex_catch_This_Any_propagation_commit_or_ex_or_caught_is_invalid() {
monkeyDao.insert("required_commit_or_ex_catch_This_Any_propagation_commit_or_ex_or_caught_is_invalid_A");
this.required_commit_or_ex_catch_This_Any_propagation_commit_or_ex_or_caught_is_invalid_this("required_commit_or_ex_catch_This_Any_propagation_commit_or_ex_or_caught_is_invalid_this");
}
@Override
@Transactional(rollbackFor = Exception.class, propagation = Propagation.NEVER)
public void required_commit_or_ex_catch_This_Any_propagation_commit_or_ex_or_caught_is_invalid_this(String name) {
monkeyDao.insert(name);
}
@Override
@Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
public void required_commit_or_ex_catch_Spring_Any_propagation_commit_or_ex_or_caught_invalid() {
monkeyDao.insert("required_commit_or_ex_catch_Spring_Any_propagation_commit_or_ex_or_caught_invalid_A");
txAService.required_commit_or_ex_catch_Spring_Any_propagation_commit_or_ex_or_caught_invalid_Spring("required_commit_or_ex_catch_Spring_Any_propagation_commit_or_ex_or_caught_invalid_Spring");
}
@Override
@Transactional(rollbackFor = Exception.class, propagation = Propagation.NEVER)
public void required_commit_or_ex_catch_Spring_Any_propagation_commit_or_ex_or_caught_invalid_Spring(String name) {
monkeyDao.insert(name);
}
}
ServiceB Interface
package center.leon.springtx.service;
public interface TxBService {
void required_commit_NoTx_commit(String name);
void required_commit_NoTx_Ex(String name);
void required_commit_Required_commit(String name);
void required_commit_Required_Ex(String name);
void required_commit_Required_Ex_Caught(String name);
void required_commit_Required_New_Commit(String name);
void required_commit_Required_New_Ex(String name);
void required_commit_Required_New_Ex_Caught(String name);
void required_Ex_Required_New_commit(String name);
void required_commit_Required_Nested_Commit(String name);
void required_commit_Required_Nested_Ex(String name);
void required_commit_Required_Nested_Ex_Caught(String name);
}
ServiceBImpl Class
package center.leon.springtx.service.impl;
import center.leon.springtx.dao.MonkeyDao;
import center.leon.springtx.service.TxBService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
@Service
public class TxBServiceImpl implements TxBService {
@Autowired
private MonkeyDao monkeyDao;
@Override
public void required_commit_NoTx_commit(String name) {
monkeyDao.insert(name);
}
@Override
public void required_commit_NoTx_Ex(String name) {
monkeyDao.insert(name);
int i = 0 / 0;
}
@Override
@Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
public void required_commit_Required_commit(String name) {
monkeyDao.insert(name);
}
@Override
@Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
public void required_commit_Required_Ex(String name) {
monkeyDao.insert(name);
int i = 0 / 0;
}
@Override
@Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
public void required_commit_Required_Ex_Caught(String name) {
monkeyDao.insert(name);
int i = 0 / 0;
}
@Override
@Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRES_NEW)
public void required_commit_Required_New_Commit(String name) {
monkeyDao.insert(name);
}
@Override
@Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRES_NEW)
public void required_commit_Required_New_Ex(String name) {
monkeyDao.insert(name);
int i = 0 / 0;
}
@Override
@Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRES_NEW)
public void required_commit_Required_New_Ex_Caught(String name) {
monkeyDao.insert(name);
int i = 0 / 0;
}
@Override
@Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRES_NEW)
public void required_Ex_Required_New_commit(String name) {
monkeyDao.insert(name);
}
@Override
@Transactional(rollbackFor = Exception.class, propagation = Propagation.NESTED)
public void required_commit_Required_Nested_Commit(String name) {
monkeyDao.insert(name);
}
@Override
@Transactional(rollbackFor = Exception.class, propagation = Propagation.NESTED)
public void required_commit_Required_Nested_Ex(String name) {
monkeyDao.insert(name);
int i = 0 / 0;
}
@Override
@Transactional(rollbackFor = Exception.class, propagation = Propagation.NESTED)
public void required_commit_Required_Nested_Ex_Caught(String name) {
monkeyDao.insert(name);
int i = 0 / 0;
}
}