jta mysql_springboot + jta + mysql + mongo 分布式(多种数据源)事务

本文介绍了如何在SpringBoot中使用jta和Atomikos来实现MySQL和MongoDB的分布式事务管理。通过配置AtomikosDataSourceBean和自定义UserTransactionImp,实现了对两种不同数据源的事务支持。文章详细讲解了配置过程和关键代码,包括事务开始、提交和回滚的处理,以及事务管理类的交互。
摘要由CSDN通过智能技术生成

该文章讲的不是仅mysql的多数据源。

环境:

mysql: 5.1.27

mongodb: 4.2.2

springboot: 2.2.2

在前n天遇到一个业务是用到mysql和mongo。都有写操作,想到急需一个事务管理的东东,上网搜了一遍,发现mysql和mongo是各自独立事务管理的。mongo用的是 MongoTransactionManager(要依赖的等会给),mysql用的是 DataSourceTransactionManager 。

刚开始我选择的一种思路是给两个 TransactionManager @Bean方式配置上。发现 @Transactional 注解方式仅支持一种事务管理(我看了一下代码方式的事务好像也是有冲突,具体冲突等会讲)@Transactional(transactionManager = "transactionManager")。这个仅支持一种事务管理,要从一个叫 AbstractPlatformTransactionManager 的类说起。AbstractPlatformTransactionManager 是所有事务管理的一个抽象类,其作用是给spring可调用组件式的事务管理继承类(如MongoTransactionManager、DataSourceTransactionManager)。

查看 AbstractPlatformTransactionManager 源代码,该类的开始事务流程需要自行去查看。

下面我要说一下与整个事务改造的相关类。

AbstractPlatformTransactionManager 有一个顺序特别要注意,就是子事务管理类操作完doBegin后才会进行 TransactionSynchronizationManager 相关的初始化,该类与事务上下文有着紧密的联系,事务该不该做都会先咨询该类。该类由一堆 ThreadLocal 管理事务的独立,可自行查看源码。

查看 TransactionSynchronizationManager 后得知,一个线程紧允许一个事务管理进行开启事务。由于 MongoTransactionManager 与 DataSourceTransactionManager 都会操作 TransactionSynchronizationManager 导致在各自开启事务时均到该类操作 synchronizations (一个线程对应一个事务“链”,该变量存放的是resourceList)

显然两个事务管理都配置的方式不能满足我的需求

上网查资料重新整理思路,发现了一个新东西,jta+atomikos 分布式事务管理,但网上的案例全是mysql多数据源。

当时抱着不管三七二十一都加一下依赖来看看这东西玩法的心态就试了一下,通过不断阅读源码与理解,最后就搭建出来了。

先添加以下依赖:

implementation 'org.springframework.boot:spring-boot-starter-data-mongodb'

implementation 'org.springframework.boot:spring-boot-starter-jta-atomikos'

implementation 'org.springframework.boot:spring-jdbc'

implementation 'mysql:mysql-connector-java:8.0.11'

看了一下 jta-atomikos 有一堆*Imp的类,一开始就想着估计是给用户自定义的吧。配置的时候也是创建一个叫UserTransactionImp() 的东西,注入给 Jta 的事务管理 JtaTransactionManager 。看了没啥特殊的依赖,直接复制他的源码,创建自己的 UserTransactionImp。

这里要特别注意的是:使用了 jta-atomikos 会直接管理 mysql 的事务,使用的是 atomikos 的 xa 事务。只需要单独处理 mongo 的事务

package com.shero.sport.web.conf;

import com.atomikos.icatch.jta.UserTransactionManager;

import com.shero.comm.constant.TransactionManagerConstant;

import com.shero.sport.service.utils.MongoUtils;

import org.springframework.beans.factory.ObjectProvider;

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.boot.autoconfigure.transaction.TransactionManagerCustomizers;

import org.springframework.boot.context.properties.ConfigurationProperties;

import org.springframework.boot.jta.atomikos.AtomikosDataSourceBean;

import org.springframework.context.annotation.Bean;

import org.springframework.context.annotation.Configuration;

import org.springframework.context.annotation.Primary;

import org.springframework.core.env.Environment;

import org.springframework.data.mongodb.MongoDbFactory;

import org.springframework.data.mongodb.MongoTransactionManager;

import org.springframework.jdbc.datasource.DataSourceTransactionManager;

import org.springframework.transaction.jta.JtaTransactionManager;

import javax.sql.DataSource;

import javax.transaction.UserTransaction;

import java.util.Properties;

@Configuration

public class TransactionConfiguration {

@Autowired Environment env;

// @Bean(name = TransactionManagerConstant.MONGO_TRANSACTION_MANAGER)

public MongoTransactionManager mongoTransactionManager(MongoDbFactory factory) {

return new MongoTransactionManager(factory);

}

// @Bean

public DataSourceTransactionManager transactionManager(DataSource dataSource,

ObjectProvider transactionManagerCustomizers) {

DataSourceTransactionManager transactionManager = new DataSourceTransactionManager(dataSource);

transactionManagerCustomizers.ifAvailable((customizers) -> customizers.customize(transactionManager));

return transactionManager;

}

@Bean(name = "primaryMysql")

@Primary

@ConfigurationProperties(prefix = "spring.datasource")

public DataSource primaryDataSource() throws Exception {

AtomikosDataSourceBean ds = new AtomikosDataSourceBean();

ds.setXaDataSourceClassName("com.alibaba.druid.pool.xa.DruidXADataSource");

ds.setUniqueResourceName("primaryMysql");

ds.setPoolSize(5);

ds.setXaProperties(build("spring.datasource."));

return ds;

}

@Bean(name = TransactionManagerConstant.TRANSACTION_MANAGER)

@Primary

@Autowired

public JtaTransactionManager transactionManager(MongoDbFactory factory, MongoUtils mongoUtils) {

UserTransactionManager userTransactionManager = new UserTransactionManager();

UserTransaction userTransaction = new JtaTransactionImp(mongoTransactionManager(factory), mongoUtils);

return new JtaTransactionManager(userTransaction, userTransactionManager);

}

private Properties build(String prefix) {

Properties prop = new Properties();

prop.put("url", env.getProperty(prefix + "url"));

prop.put("username", env.getProperty(prefix + "username"));

prop.put("password", env.getProperty(prefix + "password"));

prop.put(&

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值