关于JTA事务和XA事务的介绍
何为分布式事务
一个事务包含多个操作,多个操作操作了多个数据源,这样的事务称为分布式事务。
案例
为什么不能简单的借助数据源的本地事务
用数据源本地事务代码案例
Con1 = db1.getConn..;
Con2 = db2.getConn..;
Try{
con1.insert….
con2.update….
con1.commit;
con2.commit;
}catche(Exception e){
con1.rollback;
con2.rollback;
}
现在会出现一个问题,就是会有第一个事务提交了但是第二个事务失败了,就保证不了一致性了。所以引入了事务管理器
分布式事务管理需要做什么
- 协调各个数据源的提交、回滚、以及应对通信异常的的管理机制
- 数据源本身需要支持这种机制(Innodb引擎是支持的)
- 应对应用的故障恢复机制
事务管理器是协调数据源的,所以需要一套规范的协议
应对网络、主机故障等 事务管理器和数据源需要记录相关日志
就产生了2套规范 :XA 规范和JTA
何为XA 规范
-
是一套跨语言的标准
XA事务的处理模型
-
XA的流程
3.XA的2阶段提交 2PC
JTA 是什么
Java Transaction API
java根据XA规范提供的事务处理标准
目的:统一一个API 简化学习
<dependency>
<groupId>javax.transaction</groupId>
<artifactId>javax.transaction-api</artifactId>
<version>1.3</version>
</dependency>
定义了一套的接口
开源的实现 TM 提供商
- Java Open Transaction Manager (JOTM)
- JBoss TS
- Bitronix Transaction Manager (BTM)
- Atomikos
- Narayana
RM的提供商
Spring集成JTA(Atomikos案例)
maven依赖
单纯使用Spring
<!-- jta api -->
<dependency>
<groupId>javax.transaction</groupId>
<artifactId>javax.transaction-api</artifactId>
<version>1.3</version>
</dependency>
<!-- atomikos 数据库的TM组件 -->
<dependency>
<groupId>com.atomikos</groupId>
<artifactId>transactions-jdbc</artifactId>
<version>4.0.6</version>
</dependency>
<!-- atomikos JMS 有MQ需要事务管理时加入 -->
<dependency>
<groupId>com.atomikos</groupId>
<artifactId>transactions-jms</artifactId>
<version>4.0.6</version>
</dependency>
Spring boot
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jta-atomikos</artifactId>
<version>2.1.1.RELEASE</version>
</dependency>
bean的配置
<!-- xa数据源1 -->
<bean id="db1DataSource" class="com.atomikos.jdbc.AtomikosDataSourceBean"
init-method="init" destroy-method="close">
<!-- 给数据源取个唯一区分的名称 -->
<property name="uniqueResourceName" value="mysql/db01" />
<!-- 真正使用的 XA DataSource 类名 -->
<property name="xaDataSourceClassName"
value="com.alibaba.druid.pool.xa.DruidXADataSource" />
<!-- 数据源连接相关配置参数 这个是指定 xaDataSourceClassName指定的XA数据源类需要的参数-->
<property name="xaProperties">
<props>
<prop key="url">${db1.jdbc.url}</prop>
<prop key="username">${jdbc.username}</prop>
<prop key="password">${jdbc.password}</prop>
<prop key="initialSize">1</prop>
<prop key="minIdle">1</prop>
<prop key="maxActive">10</prop>
</props>
</property>
</bean>
<!-- xa数据源2 -->
<bean id="db2DataSource" class="com.atomikos.jdbc.AtomikosDataSourceBean"
init-method="init" destroy-method="close">
<!-- 给数据源取个唯一区分的名称 -->
<property name="uniqueResourceName" value="mysql/db02" />
<!-- 真正使用的 XA DataSource 类名 -->
<property name="xaDataSourceClassName"
value="com.alibaba.druid.pool.xa.DruidXADataSource" />
<!-- 数据源连接相关配置参数 这个是指定 xaDataSourceClassName指定的XA数据源类需要的参数 -->
<property name="xaProperties">
<props>
<prop key="url">${db2.jdbc.url}</prop>
<prop key="username">${jdbc.username}</prop>
<prop key="password">${jdbc.password}</prop>
<prop key="initialSize">1</prop>
<prop key="minIdle">1</prop>
<prop key="maxActive">10</prop>
</props>
</property>
</bean>
<bean id="jdbcTemplate1" class="org.springframework.jdbc.core.JdbcTemplate" scope="prototype">
<property name="dataSource" ref="db1DataSource" />
</bean>
<bean id="jdbcTemplate2" class="org.springframework.jdbc.core.JdbcTemplate" scope="prototype">
<property name="dataSource" ref="db2DataSource" />
</bean>
<!-- ******************* atomikos jta 事务管理配置 begin ********************************** -->
<!-- UserTransactionServiceImp -->
<bean id="userTransactionService"
class="com.atomikos.icatch.config.UserTransactionServiceImp"
init-method="init" destroy-method="shutdownForce">
<constructor-arg>
<!-- IMPORTANT: specify all Atomikos properties here -->
<props>
<prop key="com.atomikos.icatch.service">
com.atomikos.icatch.standalone.UserTransactionServiceFactory
</prop>
<!-- 事务日志存放地址参数 -->
<prop key="com.atomikos.icatch.log_base_name">jtalog</prop>
<prop key="com.atomikos.icatch.log_base_dir">f:/test</prop>
</props>
</constructor-arg>
</bean>
<!-- 配置TransactionManager AtomikosTransactionManager -->
<bean id="AtomikosTransactionManager"
class="com.atomikos.icatch.jta.UserTransactionManager"
init-method="init" destroy-method="close"
depends-on="userTransactionService">
<!-- IMPORTANT: disable startup because the userTransactionService above does this -->
<property name="startupTransactionService" value="false"/>
<!-- when close is called,should we force transactions to terminate or not? -->
<property name="forceShutdown" value="false" />
</bean>
<!-- 配置 UserTransaction -->
<bean id="AtomikosUserTransaction"
class="com.atomikos.icatch.jta.UserTransactionImp"
depends-on="userTransactionService">
<!-- 默认是事务超时时长 300秒 -->
<property name="transactionTimeout" value="300" />
</bean>
<!-- 配置jta事务管理器,使用 Atomikos的 TransactionManager、UserTransaction -->
<bean id="JtaTransactionManager"
class="org.springframework.transaction.jta.JtaTransactionManager"
depends-on="userTransactionService">
<property name="transactionManager" ref="AtomikosTransactionManager" />
<property name="userTransaction" ref="AtomikosUserTransaction" />
</bean>