46--Spring @Transactional声明式事物(三)事物创建

1.引

上一节已经分析了了在单service单方法下的事物创建过程以及其后续处理工作,当然还缺少真正创建事物的分析,本篇接续。先来回顾一下事物创建的代码片段:

try {
    boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER);
    // 创建DefaultTransactionStatus对象实例
    DefaultTransactionStatus status = newTransactionStatus(
            definition,
            transaction,
            true,
            newSynchronization,
            debugEnabled,
            suspendedResources);
    // 开启事物
    doBegin(transaction, definition);
    // 初始化事务同步。
    prepareSynchronization(status, definition);
    return status;
}
2.创建DefaultTransactionStatus对象
/**
 * 创建DefaultTransactionStatus实例
 * Create a TransactionStatus instance for the given arguments.
 */
protected DefaultTransactionStatus newTransactionStatus(
        TransactionDefinition definition,
        @Nullable Object transaction,
        boolean newTransaction,
        boolean newSynchronization,
        boolean debug,
        @Nullable Object suspendedResources) {

    boolean actualNewSynchronization = newSynchronization && !TransactionSynchronizationManager.isSynchronizationActive();

    return new DefaultTransactionStatus(
            transaction,
            newTransaction,
            actualNewSynchronization,
            definition.isReadOnly(),
            debug,
            suspendedResources);
}

//构造方法
public DefaultTransactionStatus(
            @Nullable Object transaction,
            boolean newTransaction,
            boolean newSynchronization,
            boolean readOnly,
            boolean debug,
            @Nullable Object suspendedResources) {

    this.transaction = transaction;
    this.newTransaction = newTransaction;
    this.newSynchronization = newSynchronization;
    this.readOnly = readOnly;
    this.debug = debug;
    this.suspendedResources = suspendedResources;
}
3.开启事物

针对不同的事物管理器会有不同的事物开启过程,本例我们只看DataSourceTransactionManager下的事物开启过程:

protected void doBegin(Object transaction, TransactionDefinition definition) {
    DataSourceTransactionObject txObject = (DataSourceTransactionObject) transaction;
    Connection con = null;

    try {
        // ConnectionHolder简介:包装JDBC连接的资源容器。DataSourceTransactionManager将该类的实例绑定到特定数据源的线程。
        // 如果txObject没有ConnectionHolder或者connectionHolder并没有加同步锁,则为其设置ConnectionHolder并加同步锁
        if (!txObject.hasConnectionHolder() || txObject.getConnectionHolder().isSynchronizedWithTransaction()) {
            // 从数据源获取连接
            Connection newCon = obtainDataSource().getConnection();
            if (logger.isDebugEnabled()) {
                logger.debug("Acquired Connection [" + newCon + "] for JDBC transaction");
            }
            // 设置DataSourceTransactionObject的ConnectionHolder对象
            txObject.setConnectionHolder(new ConnectionHolder(newCon), true);
        }

        // 设置同步锁标记
        txObject.getConnectionHolder().setSynchronizedWithTransaction(true);

        // 从ConnectionHolder对象中获取连接
        con = txObject.getConnectionHolder().getConnection();

        // 设置连接的只读属性和数据库事物隔离级别
        Integer previousIsolationLevel = DataSourceUtils.prepareConnectionForTransaction(con, definition);
        txObject.setPreviousIsolationLevel(previousIsolationLevel);

        // Switch to manual commit if necessary. This is very expensive in some JDBC drivers,
        // so we don't want to do it unnecessarily
        // (for example if we've explicitly configured the connection pool to set it already).
        // 如果需要,切换到手动提交。
        // 在某些JDBC驱动程序中,这是非常昂贵的,所以我们不想做不必要的事情
        // (例如,如果我们已经显式地配置了连接池来设置它)。
        // 所以:如果连接设置了自动提交,这里要将其转换为手动提交
        if (con.getAutoCommit()) {
            txObject.setMustRestoreAutoCommit(true);
            if (logger.isDebugEnabled()) {
                logger.debug("Switching JDBC Connection [" + con + "] to manual commit");
            }
            con.setAutoCommit(false);
        }

        // 设置当前事物只读,如果定义了只读属性为true
        prepareTransactionalConnection(con, definition);
        // 设置当前事物为已激活
        txObject.getConnectionHolder().setTransactionActive(true);

        // 设置超时时间(如果超时时间不等于默认超时时间)
        int timeout = determineTimeout(definition);
        if (timeout != TransactionDefinition.TIMEOUT_DEFAULT) {
            txObject.getConnectionHolder().setTimeoutInSeconds(timeout);
        }

        // Bind the connection holder to the thread.
        // 绑定ConnectionHolder到当前线程
        if (txObject.isNewConnectionHolder()) {
            // 即TransactionSynchronizationManager类的resources对象:
            // 该对象保存每个事物线程对应的connection或session等类型的资源
            // private static final ThreadLocal<Map<Object, Object>> resources = new NamedThreadLocal<>("Transactional resources");
            TransactionSynchronizationManager.bindResource(obtainDataSource(), txObject.getConnectionHolder());
        }
    }

    // 异常处理
    catch (Throwable ex) {
        if (txObject.isNewConnectionHolder()) {
            DataSourceUtils.releaseConnection(con, obtainDataSource());
            txObject.setConnectionHolder(null, false);
        }
        throw new CannotCreateTransactionException("Could not open JDBC Connection for transaction", ex);
    }
}

该方法也比较简单,相信大家都能看懂,其中关于ConnectionHolder(前文没有讲解)对象,也已经在注释里做过介绍了。

4.初始化事物同步
/**
 * 根据需要初始化事务同步。
 * Initialize transaction synchronization as appropriate.
 */
protected void prepareSynchronization(DefaultTransactionStatus status, TransactionDefinition definition) {
    if (status.isNewSynchronization()) {
        // 设置事物激活状态
        TransactionSynchronizationManager.setActualTransactionActive(status.hasTransaction());
        // 设置事物隔离级别
        TransactionSynchronizationManager.setCurrentTransactionIsolationLevel(
                definition.getIsolationLevel() != TransactionDefinition.ISOLATION_DEFAULT ? definition.getIsolationLevel() : null);
        // 设置事物只读属性
        TransactionSynchronizationManager.setCurrentTransactionReadOnly(definition.isReadOnly());
        // 设置事物名称
        TransactionSynchronizationManager.setCurrentTransactionName(definition.getName());
        // 激活当前线程的事务同步。事务管理器在事务开始时调用。
        TransactionSynchronizationManager.initSynchronization();
    }
}

总体来讲上面的内容还是比较简单的,不做过多的分析了。

5.其他事物特性处理

以上分析的都是基于单service下单个方法调用的事物创建过程,且当前不存在事物,那么对于其它的事物的特性呢?接下来就分析一下其他的特性,其实前面的章节已经有过简单的介绍了,这里再详细分析下。对于PROPAGATION_NESTED特性会直接抛出异常。

那么下面介绍一下PROPAGATION_SUPPORTS、PROPAGATION_NOT_SUPPORTED、PROPAGATION_NEVER特性事物处理过程,先来看一下代码片段:

// Create "empty" transaction: no actual transaction, but potentially synchronization.
if (definition.getIsolationLevel() != TransactionDefinition.ISOLATION_DEFAULT && logger.isWarnEnabled()) {
    logger.warn("Custom isolation level specified but no actual transaction initiated; "
            + "isolation level will effectively be ignored: " + definition);
}
boolean newSynchronization = (getTransactionSynchronization() == SYNCHRONIZATION_ALWAYS);
return prepareTransactionStatus(
        definition,
        null,
        true,
        newSynchronization,
        debugEnabled,
        null);
protected final DefaultTransactionStatus prepareTransactionStatus(
        TransactionDefinition definition,
        @Nullable Object transaction,
        boolean newTransaction,
        boolean newSynchronization,
        boolean debug,
        @Nullable Object suspendedResources) {

    DefaultTransactionStatus status = newTransactionStatus(
            definition,
            transaction,
            newTransaction,
            newSynchronization,
            debug,
            suspendedResources);

    prepareSynchronization(status, definition);
    return status;
}

从代码里可以看到,该处理与创建真正的事物的过程相似,只是传递的参数不同罢了。大家可以多设定几种传播特性,跟踪一下代码即可。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 156,423评论 4 359
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 66,339评论 1 289
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 106,241评论 0 237
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,503评论 0 203
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 51,824评论 3 285
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,262评论 1 207
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,615评论 2 309
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,337评论 0 194
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 33,989评论 1 238
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,300评论 2 240
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 31,829评论 1 256
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,193评论 2 250
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,753评论 3 230
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 25,970评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,708评论 0 192
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,295评论 2 267
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,207评论 2 258

推荐阅读更多精彩内容

  • 1.引 上一节分析了Spring实现事物管理的步骤,本篇分析Spring事物的创建过程。 2.事物创建方法简析 最...
    闲来也无事阅读 780评论 0 5
  • 很多人喜欢这篇文章,特此同步过来 由浅入深谈论spring事务 前言 这篇其实也要归纳到《常识》系列中,但这重点又...
    码农戏码阅读 4,651评论 2 59
  • springAop:面向切面的编程 应用场景:权限控制、事物管理、日志打印等等,就是在不同的方法中重复用到相同的代...
    HJJ_3c00阅读 315评论 0 0
  • 有时候太久没写东西,脑袋里总是乱做一团,又或者空无一物。 也许是经历的事情太多了,也许是这充满磨练的一年有你的陪伴...
    深夜卡片阅读 817评论 0 0
  • 每个人都有自己的选择,不要随波逐流,关注你的内心,用心生活,生活应该过的洒脱,不要在意别人的眼光,做自己就是最好的...
    sunshine1980阅读 75评论 0 0