• 【事务】- mysql事务和neo4j事务冲突导致mysql事务不生效


    背景:需要全量更新数据,先删除再插入,插入失败则回滚删除操作,所以把两个数据库操作放在统一事务中。理论上来说,是很简单的事情,但是耗费了两天半的时间解决。

    问题:插入失败,删除操作并未回滚。排查常见的事务不生效原因,均没有问题。如:

    1. 事务注解只能在public方法上才会生效
    2. 同一个类中方法间调用会导致事务不生效,A调用B,A没有事务,B有事务,AB处于同一个类ClassA中,则导致B的事务不生效。解决方法有:
      1. 在ClassA类中注入自己,通过ClassA.B()进行调用
      2. 新建一个类ClassB,将B方法放入ClassB中,在ClassA中注入ClassB,进行调用
    3. 异常被try-catch住
    4. 类没有被Spring管理,比如忘记加@Service注解
    5. 数据库表不支持事务,比如用了MyISAM,需要查看数据库表使用的引擎类型。
    6. 没有开启事务管理器,但如果使用springboot会自动开启。并不需要特殊配置。

    脑袋疼....根本找不到问题原因啊,甚至都debug到源码上了,看到也是进了事务的。

    后来定位到是事务管理器的问题,查看数据库数据源配置,clickhouse的数据库显式配置了事务管理器。

    1. @Bean(name = "clusterTransactionManager")
    2. public DataSourceTransactionManager masterTransactionManager() {
    3. return new DataSourceTransactionManager(masterDataSource());
    4. }

    所以相当于是在用clickhouse的事务管理器去管理mysql的事务,怎么可能生效嘛???

    把clickhouse的事务管理器注释掉,在mysq的数据库连接配置中显式配置事务管理器。

    1. @Bean(name = "mySqlTransactionManager")
    2. public DataSourceTransactionManager dataSourceTransactionManager() throws Exception {
    3. return new DataSourceTransactionManager(mysqlDataSource());
    4. }

    事务终于生效了!删除操作终于回滚了!但是我同事同样的代码事务依旧没有生效.....

    比对了下代码是因为我在pom里引入了jpa的依赖,误打误撞jpa生效了,去除jpa的依赖后,neo4j事务管理器的优先级最高,接下来是spring自动生成的事务管理器等等等等,可以打印查看下。

    1. <dependency>
    2. <groupId>org.springframework.bootgroupId>
    3. <artifactId>spring-boot-starter-data-jpaartifactId>
    4. dependency>

    启动类加上如下,可以进行打印。因为该项目不需要neo4j,所以就把数据源配置和引用依赖全删除了。一定要删除依赖,不然还是会加载neo4j的事务管理器。优先级就是这么高没办法。。。

    1. @Bean
    2. public Object testBean(@Qualifier("transactionManager") PlatformTransactionManager platformTransactionManager) {
    3. System.out.println(">>>>>>>>>>" + platformTransactionManager.getClass().getName());
    4. return new Object();
    5. }

    那么问题来了,如果的确有需要用到neo4j,那还怎么让事务生效。加上如下代码即可,有多少数据库需要进行事务管理传参就加多少即可。

    1. @SuppressWarnings("SpringJavaInjectionPointsAutowiringInspection")
    2. @Configuration
    3. @DependsOn("sessionFactory")
    4. public class TransactionAspect {
    5. ThreadLocal<TransactionStatus> transactionStatusThreadLocal = new ThreadLocal<>();
    6. /**
    7. * 定义mysql事务管理器,必须有transactionManager作为默认事务管理器
    8. *
    9. * @param dataSource
    10. * @return
    11. */
    12. @Bean("transactionManager")
    13. @Primary
    14. public DataSourceTransactionManager transactionManager(DataSource dataSource) {
    15. return new DataSourceTransactionManager(dataSource);
    16. }
    17. /**
    18. * 定义neo4j事务管理器
    19. *
    20. * @param sessionFactory
    21. * @return
    22. */
    23. @Bean("neo4jTransactionManager")
    24. public Neo4jTransactionManager neo4jTransactionManager(SessionFactory sessionFactory) {
    25. return new Neo4jTransactionManager(sessionFactory);
    26. }
    27. @Autowired
    28. @Bean(name = "multiTransactionManager")
    29. public PlatformTransactionManager multiTransactionManager(
    30. Neo4jTransactionManager neo4jTransactionManager,
    31. DataSourceTransactionManager mysqlTransactionManager) {
    32. return new ChainedTransactionManager(neo4jTransactionManager, mysqlTransactionManager);
    33. }
    34. }

  • 相关阅读:
    义乌个体户
    第5讲:SQL语句之DML类型的数据操纵语言
    如何找到‘.‘ is not recognized as an internal or external command的根本原因和解决方案
    Nexus数据备份&恢复
    Unity GC + C# GC + Lua GC原理
    同步推送?苹果计划本月推出 iOS17和iPadOS17,你的手机支持吗?
    【git】取消git代理
    label-preserving transformations
    数据思维笔记整理
    ABAP学习笔记之——第八章:报表程序
  • 原文地址:https://blog.csdn.net/wj1607162253/article/details/126059453