背景:需要全量更新数据,先删除再插入,插入失败则回滚删除操作,所以把两个数据库操作放在统一事务中。理论上来说,是很简单的事情,但是耗费了两天半的时间解决。
问题:插入失败,删除操作并未回滚。排查常见的事务不生效原因,均没有问题。如:
脑袋疼....根本找不到问题原因啊,甚至都debug到源码上了,看到也是进了事务的。
后来定位到是事务管理器的问题,查看数据库数据源配置,clickhouse的数据库显式配置了事务管理器。
- @Bean(name = "clusterTransactionManager")
- public DataSourceTransactionManager masterTransactionManager() {
- return new DataSourceTransactionManager(masterDataSource());
- }
所以相当于是在用clickhouse的事务管理器去管理mysql的事务,怎么可能生效嘛???
把clickhouse的事务管理器注释掉,在mysq的数据库连接配置中显式配置事务管理器。
- @Bean(name = "mySqlTransactionManager")
- public DataSourceTransactionManager dataSourceTransactionManager() throws Exception {
- return new DataSourceTransactionManager(mysqlDataSource());
- }
事务终于生效了!删除操作终于回滚了!但是我同事同样的代码事务依旧没有生效.....
比对了下代码是因为我在pom里引入了jpa的依赖,误打误撞jpa生效了,去除jpa的依赖后,neo4j事务管理器的优先级最高,接下来是spring自动生成的事务管理器等等等等,可以打印查看下。
- <dependency>
- <groupId>org.springframework.bootgroupId>
- <artifactId>spring-boot-starter-data-jpaartifactId>
- dependency>
启动类加上如下,可以进行打印。因为该项目不需要neo4j,所以就把数据源配置和引用依赖全删除了。一定要删除依赖,不然还是会加载neo4j的事务管理器。优先级就是这么高没办法。。。
- @Bean
- public Object testBean(@Qualifier("transactionManager") PlatformTransactionManager platformTransactionManager) {
- System.out.println(">>>>>>>>>>" + platformTransactionManager.getClass().getName());
- return new Object();
- }
那么问题来了,如果的确有需要用到neo4j,那还怎么让事务生效。加上如下代码即可,有多少数据库需要进行事务管理传参就加多少即可。
- @SuppressWarnings("SpringJavaInjectionPointsAutowiringInspection")
- @Configuration
- @DependsOn("sessionFactory")
- public class TransactionAspect {
- ThreadLocal<TransactionStatus> transactionStatusThreadLocal = new ThreadLocal<>();
-
- /**
- * 定义mysql事务管理器,必须有transactionManager作为默认事务管理器
- *
- * @param dataSource
- * @return
- */
- @Bean("transactionManager")
- @Primary
- public DataSourceTransactionManager transactionManager(DataSource dataSource) {
- return new DataSourceTransactionManager(dataSource);
- }
-
- /**
- * 定义neo4j事务管理器
- *
- * @param sessionFactory
- * @return
- */
- @Bean("neo4jTransactionManager")
- public Neo4jTransactionManager neo4jTransactionManager(SessionFactory sessionFactory) {
- return new Neo4jTransactionManager(sessionFactory);
- }
-
- @Autowired
- @Bean(name = "multiTransactionManager")
- public PlatformTransactionManager multiTransactionManager(
- Neo4jTransactionManager neo4jTransactionManager,
- DataSourceTransactionManager mysqlTransactionManager) {
- return new ChainedTransactionManager(neo4jTransactionManager, mysqlTransactionManager);
- }
- }