企业🤖AI智能体构建引擎,智能编排和调试,一键部署,支持私有化部署方案 广告
## 一、整合jta-atomikos 首先需要引入jta的依赖包,注意是JTA(事务管理),不是JPA。 ~~~ <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-jta-atomikos</artifactId> </dependency> ~~~ 双数据源配置。删掉原有其他的数据库连接配置.两个数据源的名称分别是:primary和secondary。分别访问testdb和testdb2数据库。另外注意:驱动类是MysqlXADataSource(支持分布式事务),而不是MysqlDataSource。 ~~~ primarydb: uniqueResourceName: primary xaDataSourceClassName: com.mysql.jdbc.jdbc2.optional.MysqlXADataSource xaProperties: url: jdbc:mysql://192.168.1.91:3306/testdb?useUnicode=true&characterEncoding=utf-8&useSSL=false user: test password: 4rfv$RFV exclusiveConnectionMode: true minPoolSize: 3 maxPoolSize: 10 testQuery: SELECT 1 from dual #由于采用HikiriCP,用于检测数据库连接是否存活。 secondarydb: uniqueResourceName: secondary xaDataSourceClassName: com.mysql.jdbc.jdbc2.optional.MysqlXADataSource xaProperties: url: jdbc:mysql://192.168.1.91:3306/testdb2?useUnicode=true&characterEncoding=utf-8&useSSL=false user: test password: 4rfv$RFV exclusiveConnectionMode: true minPoolSize: 3 maxPoolSize: 10 testQuery: SELECT 1 from dual #由于采用HikiriCP,用于检测数据库连接是否存活。 ~~~ ## 二、配置多数据源及事务管理 数据源DataSource、SqlSessionFactory、SqlSessionTemplate、扫描路径,对于primarydb和secondarydb都是自己一套,需要分别配置。 数据源一:primarydb ~~~ @Configuration @EnableConfigurationProperties @EnableAutoConfiguration @MapperScan(basePackages = "com.zimug.bootlaunch.generator.testdb", //注意这里 sqlSessionTemplateRef = "primarySqlSessionTemplate") public class PrimaryDataSourceJTAConfig { @Bean("primaryDataSource") @ConfigurationProperties(prefix = "primarydb") public DataSource primaryDataSource() { return new AtomikosDataSourceBean(); } @Bean("primarySqlSessionFactory") public SqlSessionFactory primarySqlSessionFactory(@Qualifier("primaryDataSource") DataSource dataSource) throws Exception { SqlSessionFactoryBean bean = new SqlSessionFactoryBean(); bean.setDataSource(dataSource); //因为Mapper和Mapper.xml我放在同一个文件夹所以不用设资源路径 //bean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath:mapper/*.xml")); bean.setTypeAliasesPackage("com.zimug.bootlaunch.generator.testdb"); //这里需要修改为你的扫描类路径 return bean.getObject(); } @Bean("primarySqlSessionTemplate") public SqlSessionTemplate primarySqlSessionTemplate( @Qualifier("primarySqlSessionFactory") SqlSessionFactory sqlSessionFactory) throws Exception { return new SqlSessionTemplate(sqlSessionFactory); } } ~~~ 数据源二:secondarydb。参照数据源一,将primary修改为secondary再配置一组。 ~~~ @Configuration @EnableConfigurationProperties @EnableAutoConfiguration @MapperScan(basePackages = "com.zimug.bootlaunch.generator.testdb2", //注意这里 sqlSessionTemplateRef = "secondarySqlSessionTemplate") public class SecondaryDataSourceJTAConfig { @Bean("secondaryDataSource") @ConfigurationProperties(prefix = "secondarydb") @Primary public DataSource secondaryDataSource() { return new AtomikosDataSourceBean(); } @Bean("secondarySqlSessionFactory") @Primary public SqlSessionFactory secondarySqlSessionFactory(@Qualifier("secondaryDataSource") DataSource dataSource) throws Exception { SqlSessionFactoryBean bean = new SqlSessionFactoryBean(); bean.setDataSource(dataSource); //bean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath:mapper/*.xml")); bean.setTypeAliasesPackage("com.zimug.bootlaunch.generator.testdb2"); //注意这里 return bean.getObject(); } @Bean("secondarySqlSessionTemplate") @Primary public SqlSessionTemplate secondarySqlSessionTemplate( @Qualifier("secondarySqlSessionFactory") SqlSessionFactory sqlSessionFactory) throws Exception { return new SqlSessionTemplate(sqlSessionFactory); } } ~~~ 虽然我们将数据源及其相关配置分成了两组,但这两组数据源使用的事务管理器必须是同一个,这样才能实现分布式事务。下面是事务管理器的配置。固定代码,一点不用改,不要纠结。不需要问张三为什么叫张三,因为他爸爸就是这么给他起名的。 ~~~ @Configuration @EnableTransactionManagement public class XATransactionManagerConfig { //User事务 @Bean(name = "userTransaction") public UserTransaction userTransaction() throws Throwable { UserTransactionImp userTransactionImp = new UserTransactionImp(); userTransactionImp.setTransactionTimeout(10000); return userTransactionImp; } //分布式事务 @Bean(name = "atomikosTransactionManager", initMethod = "init", destroyMethod = "close") public TransactionManager atomikosTransactionManager() throws Throwable { UserTransactionManager userTransactionManager = new UserTransactionManager(); userTransactionManager.setForceShutdown(false); return userTransactionManager; } //事务管理器 @Bean(name = "transactionManager") @DependsOn({ "userTransaction", "atomikosTransactionManager" }) public PlatformTransactionManager transactionManager() throws Throwable { return new JtaTransactionManager(userTransaction(),atomikosTransactionManager()); } } ~~~ ## 三、service层测试 将自动生成的代码,分别存放于testdb和testdb2两个文件夹 ![](https://box.kancloud.cn/a96cb8e34c72b97cfd56f7322a2613e3_445x293.png) 在Service层模拟异常 ~~~ @Override @Transactional public ArticleVO saveArticle(ArticleVO article) { Article articlePO = dozerMapper.map(article,Article.class); articleMapper.insert(articlePO); Message message = new Message(); message.setName("kobe"); message.setContent("退役啦"); messageMapper.insert(message); int a = 2/0; //认为制造被除数为0的异常 return article; } ~~~ 正常情况下,2组数据分别插入到testdb的article表和testdb2的message表。如果我们人为制造一个异常(如上面代码),事务回滚,二者均无法插入数据。