本文的几个关键词,分布式数据源,数据源的动态寻找,分布式事务JTA实现。
对于一些较大规模的应用,单个数据源是无法支撑起庞大的用户量,需要引入多数据源,水平层面进行分库分表,降低单个DB的负载。接下来,我们程序里里面需 要管理不同数据源之前的程序调用,保证功能是WORK的。另外,跨库就意味着之前单DB的事务就失效了,所以J2EE提出了JTA,分布式的事务管理,往 简单了说,就是2步提交(two phase),比单步提交更苛刻。实际上他有两个容器来管理,一个是资源管理器,一个是事务管理。小伙伴们可以发现,这是一个环环相扣的过程。想解决一个 问题,你就得解决这几个相关的问题。以下代码,我也是参考了前辈们的思想,进行了改造。
第一步:XA数据源定义
选定义一个抽象的父类源,这样子类可以直接继承
1 <!-- 两个数据源的功用配置,方便下面直接引用 -->
2 <bean id="abstractXADataSource" class="com.atomikos.jdbc.AtomikosDataSourceBean" init-method="init"
3 destroy-method="close" abstract="true">
4 <property name="xaDataSourceClassName" value="com.mysql.jdbc.jdbc2.optional.MysqlXADataSource"/>
5 <property name="poolSize" value="10" />
6 <property name="minPoolSize" value="10"/>
7 <property name="maxPoolSize" value="30"/>
8 <property name="borrowConnectionTimeout" value="60"/>
9 <property name="reapTimeout" value="20"/>
10 <!-- 最大空闲时间 -->
11 <property name="maxIdleTime" value="60"/>
12 <property name="maintenanceInterval" value="60" />
13 <property name="loginTimeout" value="60"/>
14 <property name="logWriter" value="60"/>
15 <property name="testQuery">
16 <value>select 1</value>
17 </property>
18
19 </bean>
20
A源2 <bean id="abstractXADataSource" class="com.atomikos.jdbc.AtomikosDataSourceBean" init-method="init"
3 destroy-method="close" abstract="true">
4 <property name="xaDataSourceClassName" value="com.mysql.jdbc.jdbc2.optional.MysqlXADataSource"/>
5 <property name="poolSize" value="10" />
6 <property name="minPoolSize" value="10"/>
7 <property name="maxPoolSize" value="30"/>
8 <property name="borrowConnectionTimeout" value="60"/>
9 <property name="reapTimeout" value="20"/>
10 <!-- 最大空闲时间 -->
11 <property name="maxIdleTime" value="60"/>
12 <property name="maintenanceInterval" value="60" />
13 <property name="loginTimeout" value="60"/>
14 <property name="logWriter" value="60"/>
15 <property name="testQuery">
16 <value>select 1</value>
17 </property>
18
19 </bean>
20
1 <!-- 配置第一个数据源 -->
2 <bean id="dataSource_a" parent="abstractXADataSource">
3 <!-- value只要两个数据源不同就行,随便取名 -->
4 <property name="uniqueResourceName" value="mysql/sitestone" />
5 <property name="xaDataSourceClassName"
6 value="com.mysql.jdbc.jdbc2.optional.MysqlXADataSource" />
7 <property name="xaProperties">
8 <props>
9 <prop key="URL">${jdbc.url.spider}</prop>
10 <prop key="user">${jdbc.username}</prop>
11 <prop key="password">${jdbc.password}</prop>
12 </props>
13 </property>
14 </bean>
2 <bean id="dataSource_a" parent="abstractXADataSource">
3 <!-- value只要两个数据源不同就行,随便取名 -->
4 <property name="uniqueResourceName" value="mysql/sitestone" />
5 <property name="xaDataSourceClassName"
6 value="com.mysql.jdbc.jdbc2.optional.MysqlXADataSource" />
7 <property name="xaProperties">
8 <props>
9 <prop key="URL">${jdbc.url.spider}</prop>
10 <prop key="user">${jdbc.username}</prop>
11 <prop key="password">${jdbc.password}</prop>
12 </props>
13 </property>
14 </bean>
B 源
1 <!-- 配置第二个数据源-->
2 <bean id="dataSource_b" parent="abstractXADataSource">
3 <!-- value只要两个数据源不同就行,随便取名 -->
4 <property name="uniqueResourceName" value="mysql/sitesttwo" />
5 <property name="xaDataSourceClassName"
6 value="com.mysql.jdbc.jdbc2.optional.MysqlXADataSource" />
7 <property name="xaProperties">
8 <props>
9 <prop key="URL">${jdbc_tb.url.spider}</prop>
10 <prop key="user">${jdbc_tb.username}</prop>
11 <prop key="password">${jdbc_tb.password}</prop>
12 </props>
13 </property>
14 </bean>
2 <bean id="dataSource_b" parent="abstractXADataSource">
3 <!-- value只要两个数据源不同就行,随便取名 -->
4 <property name="uniqueResourceName" value="mysql/sitesttwo" />
5 <property name="xaDataSourceClassName"
6 value="com.mysql.jdbc.jdbc2.optional.MysqlXADataSource" />
7 <property name="xaProperties">
8 <props>
9 <prop key="URL">${jdbc_tb.url.spider}</prop>
10 <prop key="user">${jdbc_tb.username}</prop>
11 <prop key="password">${jdbc_tb.password}</prop>
12 </props>
13 </property>
14 </bean>
基于SPRING的AbstractRoutingDataSource动态数据路由定义
1 <bean name="dynamicDatasource" class="com.***.spring.datasource.CustomerDatasource">
2 <property name="targetDataSources">
3 <map>
4 <entry key="ds_1" value-ref="dataSource_a"/>
5 <entry key="ds_2" value-ref="dataSource_b"/>
6 </map>
7 </property>
8 <property name="defaultTargetDataSource" ref="dataSource_a" />
9 </bean>
2 <property name="targetDataSources">
3 <map>
4 <entry key="ds_1" value-ref="dataSource_a"/>
5 <entry key="ds_2" value-ref="dataSource_b"/>
6 </map>
7 </property>
8 <property name="defaultTargetDataSource" ref="dataSource_a" />
9 </bean>
我这里是使用MYBATIS来进行ORM映射,配置如下
1 <bean id="sqlSessionFactorya" class="org.mybatis.spring.SqlSessionFactoryBean">
2 <property name="dataSource" ref="dataSource_a"/>
3 <property name="typeAliasesPackage" value="com.****.spring.dschange.bean" />
4 <!-- mapper和resultmap配置路径 -->
5 <property name="mapperLocations">
6 <list>
7 <!-- 表示在com.**目录下的任意包下的resultmap包目录中,以-resultmap.xml或-mapper.xml结尾所有文件 -->
8 <value>classpath:com/***/spring/dschange/mapper/ShopMapper.xml</value>
9 </list>
10 </property>
11 </bean>
12 <bean id="sqlSessionFactoryb" class="org.mybatis.spring.SqlSessionFactoryBean">
13 <property name="dataSource" ref="dataSource_b"/>
14 <property name="typeAliasesPackage" value="com.****.spring.dschange.bean" />
15 <!-- mapper和resultmap配置路径 -->
16 <property name="mapperLocations">
17 <list>
18 <!-- 表示在com.***目录下的任意包下的resultmap包目录中,以-resultmap.xml或-mapper.xml结尾所有文件 -->
19 <value>classpath:com/***/spring/dschange/mapper/ShopMapper.xml</value>
20 </list>
21 </property>
22 </bean>
2 <property name="dataSource" ref="dataSource_a"/>
3 <property name="typeAliasesPackage" value="com.****.spring.dschange.bean" />
4 <!-- mapper和resultmap配置路径 -->
5 <property name="mapperLocations">
6 <list>
7 <!-- 表示在com.**目录下的任意包下的resultmap包目录中,以-resultmap.xml或-mapper.xml结尾所有文件 -->
8 <value>classpath:com/***/spring/dschange/mapper/ShopMapper.xml</value>
9 </list>
10 </property>
11 </bean>
12 <bean id="sqlSessionFactoryb" class="org.mybatis.spring.SqlSessionFactoryBean">
13 <property name="dataSource" ref="dataSource_b"/>
14 <property name="typeAliasesPackage" value="com.****.spring.dschange.bean" />
15 <!-- mapper和resultmap配置路径 -->
16 <property name="mapperLocations">
17 <list>
18 <!-- 表示在com.***目录下的任意包下的resultmap包目录中,以-resultmap.xml或-mapper.xml结尾所有文件 -->
19 <value>classpath:com/***/spring/dschange/mapper/ShopMapper.xml</value>
20 </list>
21 </property>
22 </bean>
接下来,一个比较关键的地方是对MYBATIS的CustomSqlSessionTemplate的重写,主要是引入动态数据源sqlSessionFactory。针对不同的数据库,调用其对应的会话工厂,这对JTA是否启用,比较重要。
1 @Override
2 public SqlSessionFactory getSqlSessionFactory() {
3
4 SqlSessionFactory targetSqlSessionFactory = targetSqlSessionFactorys.get(DataSourceKeyHolder.getDataSourceKey());
5 if (targetSqlSessionFactory != null) {
6 return targetSqlSessionFactory;
7 } else if (defaultTargetSqlSessionFactory != null) {
8 return defaultTargetSqlSessionFactory;
9 } else {
10 Assert.notNull(targetSqlSessionFactorys, "Property 'targetSqlSessionFactorys' or 'defaultTargetSqlSessionFactory' are required");
11 Assert.notNull(defaultTargetSqlSessionFactory, "Property 'defaultTargetSqlSessionFactory' or 'targetSqlSessionFactorys' are required");
12 }
13 return this.sqlSessionFactory;
14 }
XML配置
2 public SqlSessionFactory getSqlSessionFactory() {
3
4 SqlSessionFactory targetSqlSessionFactory = targetSqlSessionFactorys.get(DataSourceKeyHolder.getDataSourceKey());
5 if (targetSqlSessionFactory != null) {
6 return targetSqlSessionFactory;
7 } else if (defaultTargetSqlSessionFactory != null) {
8 return defaultTargetSqlSessionFactory;
9 } else {
10 Assert.notNull(targetSqlSessionFactorys, "Property 'targetSqlSessionFactorys' or 'defaultTargetSqlSessionFactory' are required");
11 Assert.notNull(defaultTargetSqlSessionFactory, "Property 'defaultTargetSqlSessionFactory' or 'targetSqlSessionFactorys' are required");
12 }
13 return this.sqlSessionFactory;
14 }
XML配置
1 <!-- 配置自定义的SqlSessionTemplate模板,注入相关配置 -->
2 <bean id="sqlSessionTemplate" class="com.amos.spring.mybatis.CustomSqlSessionTemplate" scope="prototype">
3 <constructor-arg ref="sqlSessionFactorya" />
4 <property name="targetSqlSessionFactorys">
5 <map>
6 <entry value-ref="sqlSessionFactorya" key="ds_1"/>
7 <entry value-ref="sqlSessionFactoryb" key="ds_2"/>
8 </map>
9 </property>
10 </bean>
2 <bean id="sqlSessionTemplate" class="com.amos.spring.mybatis.CustomSqlSessionTemplate" scope="prototype">
3 <constructor-arg ref="sqlSessionFactorya" />
4 <property name="targetSqlSessionFactorys">
5 <map>
6 <entry value-ref="sqlSessionFactorya" key="ds_1"/>
7 <entry value-ref="sqlSessionFactoryb" key="ds_2"/>
8 </map>
9 </property>
10 </bean>
扫描配置
1 <bean id="mapperScannerConfigurer" class="org.mybatis.spring.mapper.MapperScannerConfigurer">
3 <property name="sqlSessionTemplateBeanName" value="sqlSessionTemplate"/>
4 <property name="markerInterface" value="com.*****.spring.dschange.mapper.SqlMapper"/>
5 </bean>
1 <!-- jta -->
2 <bean id="atomikosTransactionManager" class="com.atomikos.icatch.jta.UserTransactionManager"
3 init-method="init" destroy-method="close">
4 <property name="forceShutdown">
5 <value>true</value>
6 </property>
7 </bean>
8
9 <bean id="atomikosUserTransaction" class="com.atomikos.icatch.jta.UserTransactionImp">
10 <property name="transactionTimeout" value="300" />
11 </bean>
12
13 <bean id="springTransactionManager"
14 class="org.springframework.transaction.jta.JtaTransactionManager">
15 <property name="transactionManager">
16 <ref bean="atomikosTransactionManager" />
17 </property>
18 <property name="userTransaction">
19 <ref bean="atomikosUserTransaction" />
20 </property>
21 </bean>
22 <tx:annotation-driven transaction-manager="springTransactionManager" proxy-target-class="true" />
2 <property name="basePackage" value="com.****.spring.dschange.mapper" />2 <bean id="atomikosTransactionManager" class="com.atomikos.icatch.jta.UserTransactionManager"
3 init-method="init" destroy-method="close">
4 <property name="forceShutdown">
5 <value>true</value>
6 </property>
7 </bean>
8
9 <bean id="atomikosUserTransaction" class="com.atomikos.icatch.jta.UserTransactionImp">
10 <property name="transactionTimeout" value="300" />
11 </bean>
12
13 <bean id="springTransactionManager"
14 class="org.springframework.transaction.jta.JtaTransactionManager">
15 <property name="transactionManager">
16 <ref bean="atomikosTransactionManager" />
17 </property>
18 <property name="userTransaction">
19 <ref bean="atomikosUserTransaction" />
20 </property>
21 </bean>
22 <tx:annotation-driven transaction-manager="springTransactionManager" proxy-target-class="true" />
3 <property name="sqlSessionTemplateBeanName" value="sqlSessionTemplate"/>
4 <property name="markerInterface" value="com.*****.spring.dschange.mapper.SqlMapper"/>
5 </bean>
最后就是JTA的实现配置
1 <!-- jta -->
2 <bean id="atomikosTransactionManager" class="com.atomikos.icatch.jta.UserTransactionManager"
3 init-method="init" destroy-method="close">
4 <property name="forceShutdown">
5 <value>true</value>
6 </property>
7 </bean>
8
9 <bean id="atomikosUserTransaction" class="com.atomikos.icatch.jta.UserTransactionImp">
10 <property name="transactionTimeout" value="300" />
11 </bean>
12
13 <bean id="springTransactionManager"
14 class="org.springframework.transaction.jta.JtaTransactionManager">
15 <property name="transactionManager">
16 <ref bean="atomikosTransactionManager" />
17 </property>
18 <property name="userTransaction">
19 <ref bean="atomikosUserTransaction" />
20 </property>
21 </bean>
22 <tx:annotation-driven transaction-manager="springTransactionManager" proxy-target-class="true" />
2 <bean id="atomikosTransactionManager" class="com.atomikos.icatch.jta.UserTransactionManager"
3 init-method="init" destroy-method="close">
4 <property name="forceShutdown">
5 <value>true</value>
6 </property>
7 </bean>
8
9 <bean id="atomikosUserTransaction" class="com.atomikos.icatch.jta.UserTransactionImp">
10 <property name="transactionTimeout" value="300" />
11 </bean>
12
13 <bean id="springTransactionManager"
14 class="org.springframework.transaction.jta.JtaTransactionManager">
15 <property name="transactionManager">
16 <ref bean="atomikosTransactionManager" />
17 </property>
18 <property name="userTransaction">
19 <ref bean="atomikosUserTransaction" />
20 </property>
21 </bean>
22 <tx:annotation-driven transaction-manager="springTransactionManager" proxy-target-class="true" />
以上,XML配置相关的东西已经完成。
具体的代码,请点击GITHUB查看https://github.com/igool/spring-jta-mybatis
相关推荐
本示例“spring mybatis atomikos 多库分布式事务demo”聚焦于如何在Spring与MyBatis框架下利用Atomikos实现跨数据库的分布式事务管理。 首先,Spring是一个广泛应用的开源框架,提供了丰富的功能,包括依赖注入、...
本项目"java+spring+mybatis+mysql+RuoYi-atomikos-实现分布式事务.zip"是一个基于若依(RuoYi)框架改造的多模块分布式事务解决方案,它利用了Atomikos这一强大的分布式事务管理器。以下将详细解析这个项目的知识点...
本文将深入探讨如何使用Spring、MyBatis和Atomikos实现JTA分布式事务。 首先,让我们理解JTA的概念。Java Transaction API(JTA)是Java EE规范之一,用于处理分布式环境中的事务。它允许应用程序在不同的资源管理...
总结,结合Spring和Atomikos可以有效地处理分布式事务,确保跨多个数据源的操作在事务性语义下执行。配置包括设置Atomikos事务管理器、数据源以及事务属性,然后在业务逻辑中利用Spring的`@Transactional`注解来管理...
本教程将探讨如何利用Spring Boot、Druid、Mybatis以及Atomikos来配置多数据源并实现分布式事务。 首先,Spring Boot是Java生态系统中的一个流行框架,它简化了设置和配置过程,使得开发人员可以快速启动新项目。在...
Atomikos通过实现JTA规范,允许应用程序在不同的数据源之间进行跨系统事务处理。 JPA是Java平台上的标准ORM(Object-Relational Mapping)框架,用于管理和持久化Java对象到关系数据库。它提供了一种抽象层,使得...
本案例主要探讨如何利用Spring Boot、Atomikos、JTA(Java Transaction API)、Hibernate以及MyBatis,结合MySQL数据库,实现一个跨数据源的分布式事务解决方案。 首先,Spring Boot是一个基于Spring框架的快速开发...
Spring框架,MyBatis持久层框架,以及Atomikos这样的分布式事务协调器共同工作,可以帮助我们实现复杂的多数据源事务处理。这个“spring、mybatis、atomikos实现多数据源事务demo”就是为了解决这一问题而设计的。 ...
总的来说,这个DEMO旨在帮助开发者理解如何在Java应用中实现多数据源和分布式事务,涉及到的核心技术包括Spring的多数据源支持、Mybatis的持久层操作以及Atomikos的事务协调。通过实践这个DEMO,开发者可以深入掌握...
本教程将详细讲解如何使用Spring Boot、Druid和Mybatis来实现JTA(Java Transaction API)分布式事务。这是一项高级技术,它允许在多数据库环境或者微服务架构中进行一致性的数据操作。 首先,让我们了解什么是JTA...
Spring Boot、MyBatis 和 Atomikos 的结合提供了一种解决方案,用于处理多数据源的分布式事务管理。以下是对这个主题的详细阐述。 首先,Spring Boot 是一个基于 Spring 框架的轻量级开发工具,它简化了配置过程并...
Atomikos可以与Spring无缝集成,通过实现XAResource接口,它能够协调不同的数据源,确保在分布式环境下的ACID(原子性、一致性、隔离性和持久性)特性。 配置Spring、MyBatis和Atomikos进行分布式事务处理通常涉及...
综上所述,这个项目是一个利用 Maven 构建的 Spring Boot 应用,它整合了多数据源、JTA 来处理分布式事务,使用 MyBatis 作为持久层框架,并且集成了某种模板引擎来生成动态页面。这样的设计使得项目具备处理大规模...
本示例中的"spring、mybatis、atomikos实现DB2、Mysql多数据源事务demo"提供了一个实用的框架,演示了如何在Spring框架中结合MyBatis持久层框架以及Atomikos事务管理器来处理来自DB2和MySQL两个不同数据库的数据源...
7. 数据源配置:由于涉及到多数据源,你需要为每个数据源创建单独的Atomikos数据源,并在Spring中声明这些数据源。 8. 事务边界设定:在业务代码中,通过`@Transactional`注解标记方法,声明该方法需要在事务内执行...
本篇文档主要讲述如何使用Spring Boot结合MyBatis、JTA(Java Transaction API)以及Atomikos实现多数据源的事务管理。 ### Spring Boot框架 Spring Boot是Spring家族中的一个全新框架,用于简化新Spring应用的...
4. 配置MyBatis:MyBatis需要与Spring集成,使用Spring管理SqlSessionFactory,同时需要配置使用Atomikos的数据源。 ```xml <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"> ...
本篇文章将深入探讨如何在Spring框架中结合Mybatis和Atomikos进行分布式事务管理的配置与集成。Atomikos是一款强大的开源事务处理系统,它支持JTA(Java Transaction API),可以为我们的应用程序提供分布式事务解决...
本话题主要聚焦于如何在Spring框架中结合Java Transaction API (JTA) 和 MyBatis 实现分布式事务管理。下面我们将详细探讨相关知识点。 1. **分布式事务**:在分布式系统中,事务处理跨越多个资源或服务,例如...
在这个场景下,Atomikos作为一款开源的JTA(Java Transaction API)实现,常被用来处理Spring中的分布式事务。 首先,让我们来了解一下Spring多数据源配置。在Spring中,我们可以通过DataSourceProxy和...