spring事务传播配置
在方法上添加以下注解
@Transactional(propagation = Propagation.MANDATORY)
propagation的默认值为Propagation.REQUIRED
spring一共定义了七种事务传播机制:
- PROPAGATION_REQUIRED – 支持当前事务,如果当前没有事务,就新建一个事务。
- PROPAGATION_SUPPORTS – 支持当前事务,如果当前没有事务,就以非事务方式执行。
- PROPAGATION_MANDATORY – 支持当前事务,如果当前没有事务,就抛出异常。
- PROPAGATION_REQUIRES_NEW – 新建事务,如果当前存在事务,把当前事务挂起。
- PROPAGATION_NOT_SUPPORTED – 以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。
- PROPAGATION_NEVER – 以非事务方式执行,如果当前存在事务,则抛出异常。
- PROPAGATION_NESTED – 如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则进行与PROPAGATION_REQUIRED类似的操作。
事务传播示例
spring rollback 异常
spring默认只会在遇到RuntimeException和Error时才会rollback,当自己抛出Exception异常时,并不会rollback
可通过@Transactional(propagation = Propagation.REQUIRED,rollbackFor = Exception.class)
配置
@Override
//@Transactional
public void method1(int i) {
IMGroup group = new IMGroup();
group.setId(1l);
group.setImGroupName("ceshi" + i);
groupMapper.updateByPrimaryKey(group);
try {
transactionServiceImpl.method2(i);
} catch (Exception e) {
//e.printStackTrace();
}
throw new RuntimeException();
}
@Override
@Transactional(propagation = Propagation.REQUIRED)
public void method2(int i) throws Exception {
IMGroup group = new IMGroup();
group.setId(2l);
group.setImGroupName("ceshi" + i);
groupMapper.updateByPrimaryKey(group);
throw new Exception();
}
REQUIRED
如果有事务在运行,则当前方法在这个事务内进行,如果没有事务在运行,则新建一个事务。此模式下如果内部方法异常回滚,外部方法捕获异常提交会报错rollback-only
@Override
@Transactional
public void method1(int i) {
IMGroup group = new IMGroup();
group.setId(1l);
group.setImGroupName("ceshi" + i);
groupMapper.updateByPrimaryKey(group);
try{
transactionServiceImpl.method2(i);
}catch (Exception e){}
}
@Override
@Transactional(propagation = Propagation.REQUIRED)
public void method2(int i) {
IMGroup group = new IMGroup();
group.setId(2l);
group.setImGroupName("测试" + i);
groupMapper.updateByPrimaryKey(group);
throw new RuntimeException();
}
抛出异常Transaction rolled back because it has been marked as rollback-only
NOT_SUPPORTED
以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。
@Transactional
public void method1(int i) {
IMGroup group = new IMGroup();
group.setId(1l);
group.setImGroupName("ceshi" + i);
groupMapper.updateByPrimaryKey(group);
transactionServiceImpl.method2(i);
}
@Override
@Transactional(propagation = Propagation.NOT_SUPPORTED)
public void method2(int i) {
IMGroup group = new IMGroup();
group.setId(2l);
group.setImGroupName("测试" + i);
groupMapper.updateByPrimaryKey(group);
throw new RuntimeException();
}
- 1修改失败 2修改成功
NEVER
当存在事务时,抛出异常
@Override
@Transactional
public void method1(int i) {
IMGroup group = new IMGroup();
group.setId(1l);
group.setImGroupName("ceshi" + i);
groupMapper.updateByPrimaryKey(group);
transactionServiceImpl.method2(i);
}
@Override
@Transactional(propagation = Propagation.NEVER)
public void method2(int i) {
IMGroup group = new IMGroup();
group.setId(2l);
group.setImGroupName("测试" + i);
groupMapper.updateByPrimaryKey(group);
throw new RuntimeException();
}
抛出异常org.springframework.transaction.IllegalTransactionStateException: Existing transaction found for transaction marked with propagation 'never'
MANDATORY
如果当前未在事务中则抛出异常
@Override
//@Transactional
public void method1(int i) {
IMGroup group = new IMGroup();
group.setId(1l);
group.setImGroupName("ceshi" + i);
groupMapper.updateByPrimaryKey(group);
transactionServiceImpl.method2(i);
}
@Override
@Transactional(propagation = Propagation.MANDATORY)
public void method2(int i) {
IMGroup group = new IMGroup();
group.setId(2l);
group.setImGroupName("测试" + i);
groupMapper.updateByPrimaryKey(group);
throw new RuntimeException();
}
抛出异常No existing transaction found for transaction marked with propagation 'mandatory'
REQUIRES_NEW
@Override
@Transactional
public void method1(int i) {
IMGroup group = new IMGroup();
group.setId(1l);
group.setImGroupName("ceshi" + i);
groupMapper.updateByPrimaryKey(group);
try{
transactionServiceImpl.method2(i);
}catch (Exception e){}
}
@Override
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void method2(int i) {
IMGroup group = new IMGroup();
group.setId(2l);
group.setImGroupName("测试" + i);
groupMapper.updateByPrimaryKey(group);
throw new RuntimeException();
}
}
- 1成功 2失败
- method1事务挂起,method2开启新的事务
源码分析
- AbstractPlatformTransactionManager.getTransaction()-获取事务
@Override
public final TransactionStatus getTransaction(TransactionDefinition definition) throws TransactionException {
//创建当前的事务对象
Object transaction = doGetTransaction();
//是否存在已开启的事务,判断依据为连接中的事务活动标识`txObject.getConnectionHolder().isTransactionActive()`
if (isExistingTransaction(transaction)) {
// Existing transaction found -> check propagation behavior to find out how to behave.
// 如果已存在事务,则根据不同的模式进行不同的处理
// 如配置PROPAGATION_REQUIRES_NEW的话,则调用suspend(transaction)将当前事务挂起
// 通过prepareTransactionStatus()获取新的事务,并将之前挂起的连接保存到新的DefaultTransactionStatus
return handleExistingTransaction(definition, transaction, debugEnabled);
}
// 如果配置的事务是PROPAGATION_MANDATORY,则抛出异常,该步骤一定无开启的事务
if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_MANDATORY) {
throw new IllegalTransactionStateException(
"No existing transaction found for transaction marked with propagation 'mandatory'");
}
else if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRED ||
definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRES_NEW ||
definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NESTED) {
try {
boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER);
// 创建新的事务状态
DefaultTransactionStatus status = newTransactionStatus(
definition, transaction, true, newSynchronization, debugEnabled, suspendedResources);
//如果transaction中无连接,则通过`this.dataSource.getConnection()`获取连接,获取到连接后,设置不自动提交及设置连接开启事务
doBegin(transaction, definition);
prepareSynchronization(status, definition);
return status;
}
catch (Exception ex) {
·······
}
}
else {
·····
}
}
- DataSourceTransactionManager.doGetTransaction()-获取当前的事务对象
@Override
protected Object doGetTransaction() {
DataSourceTransactionObject txObject = new DataSourceTransactionObject();
txObject.setSavepointAllowed(isNestedTransactionAllowed());
//获取到当前线程的连接
ConnectionHolder conHolder =
(ConnectionHolder) TransactionSynchronizationManager.getResource(this.dataSource);
//将当前线程的连接保存至当前事务对象中
txObject.setConnectionHolder(conHolder, false);
return txObject;
}
TransactionSynchronizationManager.getResource(this.dataSource)
-从本线程中获取ConnectionHolder
public static Object getResource(Object key) {
······
Object value = doGetResource(actualKey);
······
return value;
}
private static Object doGetResource(Object actualKey) {
//resources为Threadlocal对象
Map<Object, Object> map = resources.get();
if (map == null) {
return null;
}
// 从threadlocal中获取事务
Object value = map.get(actualKey);
······
return value;
}
- AbstractPlatformTransactionManager.suspend-挂起某个事务
protected final SuspendedResourcesHolder suspend(Object transaction) throws TransactionException {
if (TransactionSynchronizationManager.isSynchronizationActive()) {
List<TransactionSynchronization> suspendedSynchronizations = doSuspendSynchronization();
try {
Object suspendedResources = null;
if (transaction != null) {
// 将该事务的连接信息ConnectionHolder设置为null
// 并且从当前线程threadlocal中删除该连接,并且将该删除的连接返回
suspendedResources = doSuspend(transaction);
}
······
// 将连接信息封装到SuspendedResourcesHolder中并返回
return new SuspendedResourcesHolder(
suspendedResources, suspendedSynchronizations, name, readOnly, isolationLevel, wasActive);
}
catch (RuntimeException ex) {
······
}
catch (Error err) {
······
}
}
else if (transaction != null) {
// Transaction active but no synchronization active.
Object suspendedResources = doSuspend(transaction);
return new SuspendedResourcesHolder(suspendedResources);
}
else {
······
}
}