Spring5源码之Spring七种传播特性的详解

七种事务传播特性:

本篇文章主要讲解Spring事务的传播属性,先看一下下表:

传播特性名称
PROPAGATION_REQUIRED 如果当前没有事物,则新建一个事物;如果已经存在一个事物,则加入到这个事物中
PROPAGATION_SUPPORTS 支持使用当前事务,如果当前事务不存在,则不使用事务。** 解释:** 如果ServiceA.method开了事务,那么ServiceB就将自己加入ServiceA中来运行,如果ServiceA.method没有开事务,那么ServiceB自己也不开事务
PROPAGATION_MANDATORY 必须被一个开启了事务的方法来调用自己,否则报错
PROPAGATION_REQUIRES_NEW 创建一个新事务,如果当前事务存在,把当前事务挂起。 解释: ServiceB.method强制性自己开启一个新的事务,然后ServiceA.method的事务会卡住,等ServiceB事务完了自己再继续。这就是影响的回滚了,如果ServiceA报错了,ServiceB是不会受到影响的,ServiceB报错了,ServiceA也可以选择性的回滚或者是提交。
PROPAGATION_NOT_SUPPORTED 无事务执行,如果当前事务存在,把当前事务挂起。 解释: 就是ServiceB.method不支持事务,ServiceA的事务执行到ServiceB那儿,就挂起来了,ServiceB用非事务方式运行结束,ServiceA事务再继续运行。这个好处就是ServiceB代码报错不会让ServiceA回滚。
PROPAGATION_NEVER 无事务执行,如果当前有事务则抛出Exception。 解释: 不能被一个事务来调用,ServiceA.method开事务了,但是调用了ServiceB会报错
PROPAGATION_NESTED 嵌套事务,如果当前事务存在,那么在嵌套的事务中执行。如果当前事务不存在,则表现跟REQUIRED一样。 解释: 开启嵌套事务,ServiceB开启一个子事务,如果回滚的话,那么ServiceB就回滚到开启子事务的这个save point。

当前不存在事务的情况下

每次创建一个TransactionInfo的时候都会去new一个Transaction,然后去线程变量Map中拿holder,当此时线程变量的Map中holder为空时,就会视为当前情况下不存在事务,所以transaction中holder = null。

1. PROPAGATION_MANDATORY

  • 使用当前事务,如果当前没有事务,则抛出异常

    getTransaction方法中可以看到如下代码:

// 走到这里说明此时没有存在事务,如果事务的传播特性是 MANDATORY 则抛出异常
// No existing transaction found -> check propagation behavior to find out how to proceed.
if (def.getPropagationBehavior() == TransactionDefinition.PROPAGATION_MANDATORY) {
    throw new IllegalTransactionStateException(
                        "No existing transaction found for transaction marked with propagation 'mandatory'");
}

2. REQUIRED、REQUIRES_NEW、NESTED

// 如果此时不存在事务,当传播特性是 REQUIRED  REQUIRES_NEW  NESTED 都会进入if语句块
else if (def.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRED ||
                def.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRES_NEW ||
                def.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NESTED) {
    // PROPAGATION_REQUIRED PROPAGATION_REQUIRES_NEW  PROPAGATION_NESTED 都需要新建事务,、
    // 因为此时不存在事务,将null 挂起
    SuspendedResourcesHolder suspendedResources = suspend(null);
    if (debugEnabled) {
        logger.debug("Creating new transaction with name [" + def.getName() + "]: " + def);
    }
    try {
        // 注意这个方法
        // new 一个status,存放刚刚创建的transaction,然后将其标记为新事务
        // 新开一个连接的地方,非常重要
        return startTransaction(def, transaction, debugEnabled, suspendedResources);
    }
    catch (RuntimeException | Error ex) {
        resume(null, suspendedResources);
        throw ex;
    }
}

startTransaction方法:

private TransactionStatus startTransaction(TransactionDefinition definition, Object transaction,
            Boolean debugEnabled, @Nullable SuspendedResourcesHolder suspendedResources) {
    Boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER);
    // new 一个status,存放刚刚创建的transaction,然后将其标记为新事务
    // 这里的 transaction 后面的一个参数决定是否是新事务
    DefaultTransactionStatus status = newTransactionStatus(
                    definition, transaction, true, newSynchronization, debugEnabled, suspendedResources);
    // 新开一个连接的地方,非常重要
    doBegin(transaction, definition);
    prepareSynchronization(status, definition);
    return status;
}

此时会将null 挂起,此时的status变量为:

DefaultTransactionStatus status = newTransactionStatus(definition, transaction, true, newSynchronization, debugEnabled, suspendedResources);

此时的transaction中的holder依然为null,标记为新事务,接着就会执行doBegin方法了:

  • 看源码(DataTransactionManager.java)
@Override
protected void doBegin(Object transaction, TransactionDefinition definition) {
    DataSourceTransactionObject txObject = (DataSourceTransactionObject) transaction;
    Connection con = null;
    try {
        // 判断如果transaction 没有holder的话,才去dataSource中获取一个新的连接
        if (!txObject.hasConnectionHolder() ||
                            txObject.getConnectionHolder().isSynchronizedWithTransaction()) {
            // 通过 dataSource获取
            Connection newCon = obtainDataSource().getConnection();
            if (logger.isDebugEnabled()) {
                logger.debug("Acquired Connection [" + newCon + "] for JD
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值