分布式事务JTA实现

一个项目操作多个数据源的情况下,如果对事务进行管理:

    分布式事务解决方案:jta + atomikos 

结构目录:

只需要jta 目录即可,其余可忽略


1.  引入以下jar包:(前提:引入ssm需要的jar包)

            <!-- 分布式事务 jta+ atomikos -->
<dependency>
<groupId>com.atomikos</groupId>
<artifactId>transactions-jdbc</artifactId>
<version>4.0.6</version>
</dependency>
<dependency>
<groupId>javax.transaction</groupId>
<artifactId>jta</artifactId>
<version>1.1</version>

</dependency>

2. 在resource目录中编写jta配置文件:jta.xml

    <?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="
    http://www.springframework.org/schema/beans 
    http://www.springframework.org/schema/beans/spring-beans.xsd
    http://www.springframework.org/schema/context 
    http://www.springframework.org/schema/context/spring-context.xsd
    http://www.springframework.org/schema/aop
    http://www.springframework.org/schema/aop/spring-aop.xsd
    http://www.springframework.org/schema/tx
    http://www.springframework.org/schema/tx/spring-tx.xsd
    ">
  <!-- jta事务管理器 -->
    <bean class="org.springframework.transaction.jta.JtaTransactionManager" id="jtaTransactionManager">
        <property name="transactionManager">
            <bean class="com.atomikos.icatch.jta.UserTransactionManager" destroy-method="close" init-method="init">
                <property name="forceShutdown" value="true">
            </property></bean>
        </property>
        <property name="userTransaction">
            <bean class="com.atomikos.icatch.jta.UserTransactionImp">
                <property name="transactionTimeout" value="300">
            </property></bean>
        </property>
        <!-- 允许设置隔离级别 -->
         <property name="allowCustomIsolationLevels" value="true"/> <!-- 必须设置,否则程序出现异常 JtaTransactionManager does not support custom isolation levels by default -->
    </bean>
    <!-- 配置数据源 1  根据自己的数据库进行修改-->
    <bean class="com.atomikos.jdbc.AtomikosDataSourceBean" destroy-method="close" id="jtaDataSource1" init-method="init">
        <property name="uniqueResourceName" value="ds1"></property>
        <property name="xaDataSourceClassName" value="com.mysql.jdbc.jdbc2.optional.MysqlXADataSource"></property>
        <property name="xaProperties">
            <props>
                <prop key="url">
                jdbc:mysql://localhost:3306/mydb?useUnicode=true&amp;characterEncoding=UTF-8
                </prop>
                <prop key="user">root</prop>
                <prop key="password">123456</prop>
                <prop key="pinGlobalTxToPhysicalConnection">true</prop>
            </props>
        </property>
        <property name="minPoolSize" value="10"></property>
        <property name="maxPoolSize" value="100"></property>
        <property name="borrowConnectionTimeout" value="30"></property>
        <property name="testQuery" value="select 1"></property>
        <property name="maintenanceInterval" value="60"></property>
       </bean>
    <!-- 配置数据源  2 根据自己的数据库进行修改-->
    <bean class="com.atomikos.jdbc.AtomikosDataSourceBean" destroy-method="close" id="jtaDataSource2" init-method="init">
        <property name="uniqueResourceName" value="ds2"></property>
        <property name="xaDataSourceClassName" value="com.mysql.jdbc.jdbc2.optional.MysqlXADataSource"></property>
        <property name="xaProperties">
            <props>
                <prop key="url">jdbc:mysql://localhost:3306/db_test?useUnicode=true&amp;characterEncoding=UTF-8
                </prop>
                <prop key="user">root</prop>
                <prop key="password">123456</prop>
                <prop key="pinGlobalTxToPhysicalConnection">true</prop>
            </props>
        </property>
        <property name="minPoolSize" value="10"></property>
        <property name="maxPoolSize" value="100"></property>
        <property name="borrowConnectionTimeout" value="30"></property>
        <property name="testQuery" value="select 1"></property>
        <property name="maintenanceInterval" value="60"></property>
     </bean>
      <!-- 让spring管理sqlsessionfactory 使用mybatis和spring整合包中的 -->
<bean class="org.mybatis.spring.SqlSessionFactoryBean" id="sqlSessionFactory1">
        <!-- 数据库连接池 -->
        <property name="dataSource" ref="jtaDataSource1"></property>
        <!-- 加载mybatis的全局配置文件 -->
        <property name="configLocation" value="classpath:SqlMapConfig.xml"></property>
        <!-- 扫描mapper文件 -->
<property name="mapperLocations" value="classpath:cn/com/admin/jta/test01/sql/*.xml"></property>
     </bean>
      <!-- 让spring管理sqlsessionfactory 使用mybatis和spring整合包中的 -->
<bean class="org.mybatis.spring.SqlSessionFactoryBean" id="sqlSessionFactory2">
        <!-- 数据库连接池 -->
        <property name="dataSource" ref="jtaDataSource2"></property>
        <!-- 加载mybatis的全局配置文件 -->
        <property name="configLocation" value="classpath:SqlMapConfig.xml"></property>
    <!-- 扫描mapper文件 -->
<property name="mapperLocations" value="classpath:cn/com/admin/jta/test02/sql/*.xml"></property>
     </bean>
      <!--指定mybatis的mapper文件的位置-->
    <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
        <property name="basePackage" value="cn.com.admin.jta.test01"></property>
        <property name="sqlSessionFactory" ref="sqlSessionFactory1"></property>
    </bean>
        <!--指定mybatis的mapper文件的位置-->
    <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
        <property name="basePackage" value="cn.com.admin.jta.test02"></property>
        <property name="sqlSessionFactory" ref="sqlSessionFactory2"></property>
    </bean>
    
    <!--2.配置事务属性 事务管理器为 jta -->
<tx:advice transaction-manager="jtaTransactionManager" id="txAdvice">
<tx:attributes>
<!-- 针对某名称的方法,配置传播行为和隔离级别属性 -->
<tx:method name="insert*" propagation="REQUIRED"  isolation="READ_COMMITTED"/>
<tx:method name="query*" propagation="SUPPORTS"  read-only="true" />
</tx:attributes>
</tx:advice>
<!-- 3.配置事务切点 ,以及把事务切入点及事务属性关联起来: 作用在哪些类的哪些方法上 -->
<aop:config>
<aop:pointcut expression="execution(* cn.com.admin.springlearn.jta.*.*(..))"
id="txPointCut"></aop:pointcut>
<!-- 切点和事务关联 -->
<aop:advisor advice-ref="txAdvice" pointcut-ref="txPointCut"></aop:advisor>
</aop:config>
    
    <!-- 注入测试的bean -->
    <bean id="jtaTestService" class="cn.com.admin.springlearn.jta.JTATestServiceImpl"></bean>

</beans>

3. 编写2个数据源对应包下的dao接口

    自行建表测试

    public interface BusinessTest1Dao {
/**
* 添加书本
* @param business
*/
@Insert(value={"insert into business(NAME,price,num) values(#{business.name},#{business.price},#{business.num})"})
void insertBook(@Param("business") Business business);

    }

public interface BusinessTest2Dao {
/**
* 添加书本
* @param business
*/
@Insert(value={"insert into business(NAME,price,num) values(#{business.name},#{business.price},#{business.num})"})
void insertBook(@Param("business") Business business);
}

4. 测试的bean

public class JTATestServiceImpl  {
@Autowired
private BusinessTest1Dao businessTest1Dao;
@Autowired
private BusinessTest2Dao businessTest2Dao;

/**
* 同时向两个数据源插入数据
*/
public void insertBusiness() {
Business business = new Business();
business.setName("张三");
business.setNum(123);
business.setPrice(123);
businessTest1Dao.insertBook(business);
businessTest2Dao.insertBook(business);
int i = 1/0;//回滚
}

5. 测试: 由于出现异常,两个数据源对应的表都插不进去数据,实现了异常同时回滚

public class JTATest {
/**
* 初始化spring容器
*/
private static ApplicationContext ap = new ClassPathXmlApplicationContext("classpath:jta.xml");


public static void main(String[] args) {
JTATestServiceImpl jta = (JTATestServiceImpl) ap.getBean("jtaTestService");
jta.insertBusiness();
//查看数据库添加情况
System.out.println("插入完成");
}
}

  • 1
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值