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 {
            ······
		}
	}