✏️
blog
  • README
  • 2023 11
    • expect使用
  • 2023 10
    • 通过Appium给iOS应用自动化执行脚本
  • 2023 06
    • 三种ThreadLocal详解
    • 常见限流算法总结
    • 分布式ID生成算法
  • 2023 05
    • 线上机器CLOSE_WAIT连接数异常排查
    • 多数据源引发transactional事务回滚失效
  • 2023 04
    • MySQL中BufferPool
  • 2022 12
    • Linux IO
    • Netty总结
  • 2022 04
    • Thrift
  • 2022 03
    • JVM命令总结
    • 频繁FullGC定位思路
    • Redis总结
    • Spring常见问题总结
    • Kafka总结
  • 2022 02
    • Dubbo柔性服务天池大赛总结
  • 2021 12
    • 泛型中的extends和super
    • 手写一个Spring Boot Starter
  • 2021 11
    • 常用消息队列总结
  • 2021 10
    • swagger2快速使用
    • SpringBoot接口cors跨域访问
  • 2021 08
    • 常用shell命令总结
  • 2021 05
    • 线程cpu飙升排查
    • zookeeper install
  • 2021 04
    • Java虚拟机
    • [Spring Boot](2021-04/2021-04-04-Spring Boot.md)
    • [Spring MVC](2021-04/2021-04-04-Spring MVC.md)
    • 分布式ID
    • 消息队列
    • [Spring AOP](2021-04/2021-04-05-Spring AOP.md)
    • 布隆过滤器
    • Scala内核Spark阻塞排查
  • 2020 12
    • 使用Python优雅实现tail命令
  • 2020 11
    • Spark基础架构
    • 一文搞定Git
    • Spark线上问题引发的思考
  • 2020 04
    • 使用GitBook
  • 2019 05
    • SELinux、Netfilter、iptables、firewall和ufw五者关系
    • 安装npm和nodejs
    • 访问不到云服务器中的项目
  • 2019 04
    • 二叉树中节点与度数
    • 实现会话跟踪的技术有哪些
    • 计算机操作系统-死锁
    • Semaphore Count Down Latch Cyclic Barrier
    • Java内存模型
    • 双重检查锁定
    • synchronized实现底层
    • Lock接口
    • HTTP与HTTPS的区别
    • Java中线程池
    • Java中的阻塞队列
    • 排序算法
  • 2019 03
    • MySQL中索引
    • MySQL存储引擎
    • MySQL锁机制
    • n的阶乘结果后面0的个数
由 GitBook 提供支持
在本页
  • 现象
  • @Transactional注解原理
  • 简单总结

这有帮助吗?

  1. 2023 05

多数据源引发transactional事务回滚失效

上一页线上机器CLOSE_WAIT连接数异常排查下一页2023 04

最后更新于2年前

这有帮助吗?

Table of Contents generated with

现象

如图, jdbcTemplate1表示数据源1,jdbcTemplate2表示数据源2

addStudent该方法执行后,数据源1也就是第一行的数据不会被插入

数据源2执行的插入会插入

并不符合之前对transactional注解的认知,transactional底层应该是通过动态代理对添加了该注解的方法添加环绕切面

伪代码应该是

// 关闭自动提交事务
// 开启事务
try {
    // 执行方法
} catch (Throwable t) {
    // 回滚事务 
}
// 提交事务

按照上述的流程,理论上数据源1和数据源2插入的内容都应该被回滚,所以来了解下transactional的实现流程

@Transactional注解原理

快速上手

一篇不错的文章 https://blog.csdn.net/minghao0508/article/details/125834496

debug分析

核心代码主要在 TransactionAspectSupport#invokeWithinTransaction 中

大概框架和预想中的差不多

  1. 获取事务管理器

    这里是最重要的,他会根据transactional注解上的一些属性(如qualifier等)返回对应事务管理器

    如果没有指定,会返回@Primary注解对应的DataSource的事务管理器,而并不是根据哪个数据源先在方法执行就取谁,

    因为在这个层面感知不到方法里面的逻辑

    final PlatformTransactionManager tm = determineTransactionManager(txAttr);
  2. 创建事务/执行方法逻辑

     TransactionInfo txInfo = createTransactionIfNecessary(ptm, txAttr, joinpointIdentification);
  3. 执行方法逻辑/异常回滚/清理事务上下文信息

    Object retVal;
    try {
        // This is an around advice: Invoke the next interceptor in the chain.
        // This will normally result in a target object being invoked.
        retVal = invocation.proceedWithInvocation();
    }
    catch (Throwable ex) {
        // target invocation exception
        completeTransactionAfterThrowing(txInfo, ex);
        throw ex;
    }
    finally {
        cleanupTransactionInfo(txInfo);
    }
  4. 正常提交

    commitTransactionAfterReturning(txInfo);

简单总结

结论:跨数据源用transactional注解无法完全回滚,只能回滚指定数据源的数据,如果需要回滚所有数据源的数据,需要 自行定义注解(支持传入多个transactionManager)完成切面逻辑,针对多个transactionManager分别开启事务/提交事务/回滚事务

实验代码

https://github.com/icankeep/transactional-lab

自定义多数据源回滚注解

https://blog.csdn.net/u014644574/article/details/128857774

DocToc
现象
@Transactional注解原理
快速上手
debug分析
简单总结
实验代码
img.png
img.png