溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

Spring中怎么利用atomikos+druid實現(xiàn)分布式事務(wù)

發(fā)布時間:2021-08-09 16:51:58 來源:億速云 閱讀:195 作者:Leah 欄目:編程語言

今天就跟大家聊聊有關(guān)Spring中怎么利用atomikos+druid實現(xiàn)分布式事務(wù),可能很多人都不太了解,為了讓大家更加了解,小編給大家總結(jié)了以下內(nèi)容,希望大家根據(jù)這篇文章可以有所收獲。

XA是啥?

XA是由X/Open組織提出的分布式事務(wù)的架構(gòu)(或者叫協(xié)議)。XA架構(gòu)主要定義了(全局)事務(wù)管理器(Transaction Manager)和(局部)資源管理器(Resource Manager)之間的接口。XA接口是雙向的系統(tǒng)接口,在事務(wù)管理器(Transaction Manager)以及一個或多個資源管理器(Resource Manager)之間形成通信橋梁。也就是說,在基于XA的一個事務(wù)中,我們可以針對多個資源進(jìn)行事務(wù)管理,例如一個系統(tǒng)訪問多個數(shù)據(jù)庫,或即訪問數(shù)據(jù)庫、又訪問像消息中間件這樣的資源。這樣我們就能夠?qū)崿F(xiàn)在多個數(shù)據(jù)庫和消息中間件直接實現(xiàn)全部提交、或全部取消的事務(wù)。XA規(guī)范不是java的規(guī)范,而是一種通用的規(guī)范,

目前各種數(shù)據(jù)庫、以及很多消息中間件都支持XA規(guī)范。

JTA是滿足XA規(guī)范的、用于Java開發(fā)的規(guī)范。所以,當(dāng)我們說,使用JTA實現(xiàn)分布式事務(wù)的時候,其實就是說,使用JTA規(guī)范,實現(xiàn)系統(tǒng)內(nèi)多個數(shù)據(jù)庫、消息中間件等資源的事務(wù)。

JTA(Java Transaction API),是J2EE的編程接口規(guī)范,它是XA協(xié)議的JAVA實現(xiàn)。它主要定義了:

一個事務(wù)管理器的接口javax.transaction.TransactionManager,定義了有關(guān)事務(wù)的開始、提交、撤回等>操作。  一個滿足XA規(guī)范的資源定義接口javax.transaction.xa.XAResource,一種資源如果要支持JTA事務(wù),就需要讓它的資源實現(xiàn)該XAResource接口,并實現(xiàn)該接口定義的兩階段提交相關(guān)的接口。如果我們有一個應(yīng)用,它使用JTA接口實現(xiàn)事務(wù),應(yīng)用在運行的時候,就需要一個實現(xiàn)JTA的容器,一般情況下,這是一個J2EE容器,像JBoss,Websphere等應(yīng)用服務(wù)器。但是,也有一些獨立的框架實現(xiàn)了JTA,例如Atomikos, bitronix 都提供了jar包方式的JTA實現(xiàn)框架。這樣我們就能夠在Tomcat或者Jetty之類的服務(wù)器上運行使用JTA實現(xiàn)事務(wù)的應(yīng)用系統(tǒng)。在上面的本地事務(wù)和外部事務(wù)的區(qū)別中說到,JTA事務(wù)是外部事務(wù),可以用來實現(xiàn)對多個資源的事務(wù)性。它正是通過每個資源實現(xiàn)的XAResource來進(jìn)行兩階段提交的控制。感興趣的同學(xué)可以看看這個接口的方法,除了commit, rollback等方法以外,還有end(), forget(), isSameRM(), prepare()等等。光從這些接口就能夠想象JTA在實現(xiàn)兩階段事務(wù)的復(fù)雜性。

本篇以Spring MVC+Maven+Atomikos+Druid+MyBatis演示分布式事務(wù)的實現(xiàn)。

Mave 的pom.xml

<properties> <jdk.version>1.8</jdk.version> <!-- 注mysql的版本和druid的版本一定要搭配,否則會有問題,目前這兩個版本是搭配好的 --> <mysql.version>8.0.11</mysql.version> <druid.version>1.1.17</druid.version> <spring.version>5.1.8.RELEASE</spring.version> <cglib.version>3.2.12</cglib.version> <atomikos.version>5.0.0</atomikos.version> <aspectjweaver.version>1.9.4</aspectjweaver.version> <aspectjrt.version>1.5.4</aspectjrt.version> <jta.version>1.1</jta.version> <mybatise.version>3.2.0</mybatise.version> <mybatis.spring>1.2.0</mybatis.spring> <log4j.version>1.2.17</log4j.version> <junit.version>4.12</junit.version> <cglib.version>3.2.4</cglib.version></properties><dependencies> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version>${mybatise.version}</version> </dependency> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis-spring</artifactId> <version>${mybatis.spring}</version> </dependency> <dependency> <groupId>com.atomikos</groupId> <artifactId>atomikos-util</artifactId> <version>${atomikos.version}</version> </dependency> <dependency> <groupId>com.atomikos</groupId> <artifactId>transactions</artifactId> <version>${atomikos.version}</version> </dependency> <dependency> <groupId>com.atomikos</groupId> <artifactId>transactions-jta</artifactId> <version>${atomikos.version}</version> </dependency> <dependency> <groupId>com.atomikos</groupId> <artifactId>transactions-jdbc</artifactId> <version>${atomikos.version}</version> </dependency> <dependency> <groupId>com.atomikos</groupId> <artifactId>transactions-api</artifactId> <version>${atomikos.version}</version> </dependency> <dependency> <groupId>javax.transaction</groupId> <artifactId>jta</artifactId> <version>${jta.version}</version> </dependency> <dependency> <groupId>cglib</groupId> <artifactId>cglib-nodep</artifactId> <version>${cglib.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-test</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-web</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-tx</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-beans</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-jdbc</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-orm</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context-support</artifactId> <version>${spring.version}</version> </dependency> <!-- Spring Aop依賴jar --> <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjweaver</artifactId> <version>${aspectjweaver.version}</version> </dependency> <dependency> <groupId>aspectj</groupId> <artifactId>aspectjrt</artifactId> <version>${aspectjrt.version}</version> </dependency> <!-- CGLIB --> <dependency> <groupId>cglib</groupId> <artifactId>cglib</artifactId> <version>${cglib.version}</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>${mysql.version}</version> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> <version>${druid.version}</version> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>${junit.version}</version> <scopte>test</scope> </dependency></dependencies>

spring-application-context.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:p="http://www.springframework.org/schema/p"  xmlns:tx="http://www.springframework.org/schema/tx"  xmlns:context="http://www.springframework.org/schema/context"  xmlns:aop="http://www.springframework.org/schema/aop"  xmlns:mvc="http://www.springframework.org/schema/mvc"  xmlns:task="http://www.springframework.org/schema/task"  xsi:schemaLocation="http://www.springframework.org/schema/beans   http://www.springframework.org/schema/beans/spring-beans-3.1.xsd  http://www.springframework.org/schema/mvc  http://www.springframework.org/schema/mvc/spring-mvc-3.1.xsd  http://www.springframework.org/schema/context   http://www.springframework.org/schema/context/spring-context-3.1.xsd  http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task.xsd  http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.1.xsd  http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.1.xsd">     <!-- 1. 數(shù)據(jù)源配置 -->  <context:property-placeholder location="classpath*:*.properties" file-encoding="utf8" /> <bean id="utf8" class="java.lang.String"> <constructor-arg value="utf-8"></constructor-arg> </bean>  <!-- 開啟異步任務(wù)(同時開啟定時器注解掃描) -->  <task:annotation-driven />  <!-- 使用@AspectJ風(fēng)格的切面聲明 -->  <!-- <aop:aspectj-autoproxy/> -->  <!-- 使用Annotation自動注冊Bean -->  <!-- 在主容器中不掃描@Controller注解,在SpringMvc中只掃描@Controller注解 -->  <context:component-scan base-package="net.xiake6"><!-- base-package 如果多個,用“,”分隔 -->     <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller" />  </context:component-scan>   <!-- 引入Mybatis配置 -->  <!-- <import resource="spring-mybatis-atomikos-druid.xml"/> -->  <import resource="spring-mybatis-atomikos-druid.xml"/></beans>

spring-mybatis-atomikos-druid.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:jee="http://www.springframework.org/schema/jee"  xmlns:tx="http://www.springframework.org/schema/tx"   xmlns:context="http://www.springframework.org/schema/context"   xmlns:aop="http://www.springframework.org/schema/aop"  xsi:schemaLocation="http://www.springframework.org/schema/beans   http://www.springframework.org/schema/beans/spring-beans-3.0.xsd   http://www.springframework.org/schema/tx   http://www.springframework.org/schema/tx/spring-tx-3.0.xsd   http://www.springframework.org/schema/jee   http://www.springframework.org/schema/jee/spring-jee-3.0.xsd   http://www.springframework.org/schema/aop   http://www.springframework.org/schema/aop/spring-aop-3.0.xsd  http://www.springframework.org/schema/context   http://www.springframework.org/schema/context/spring-context-3.0.xsd"  default-lazy-init="true">   <context:annotation-config /> <!-- 使用Druid使為XA數(shù)據(jù)源 -->  <bean id="abstractXADataSource" class="com.atomikos.jdbc.AtomikosDataSourceBean" init-method="init" destroy-method="close" abstract="true">    <property name="xaDataSourceClassName" value="com.alibaba.druid.pool.xa.DruidXADataSource"/>    <property name="xaProperties">      <props>       <prop key="driverClassName">${jdbc.driverClassName}</prop>       <!-- 配置初始化大小、最小、最大 -->  <prop key="initialSize">10</prop>  <prop key="minIdle">3</prop>  <prop key="maxActive">100</prop>  <!-- 配置獲取連接等待超時的時間 -->  <prop key="maxWait">60000</prop>  <!-- 配置間隔多久才進(jìn)行一次檢測,檢測需要關(guān)閉的空閑連接,單位是毫秒 -->  <prop key="timeBetweenEvictionRunsMillis">60000</prop>  <!-- 配置一個連接在池中最小生存的時間,單位是毫秒 -->  <prop key="minEvictableIdleTimeMillis">300000</prop>  <prop key="validationQuery">SELECT 'x'</prop>  <prop key="testWhileIdle">true</prop>  <prop key="testOnBorrow">false</prop>  <prop key="testOnReturn">false</prop>  <!-- 配置監(jiān)控統(tǒng)計攔截的filters -->  <prop key="filters">stat</prop>      </props>    </property>  </bean>  <!-- 配置數(shù)據(jù)源一 -->  <bean id="dataSourceOne" parent="abstractXADataSource">    <property name="uniqueResourceName">      <value>dataSourceOne</value>    </property>    <property name="xaProperties">      <props>        <prop key="url">${jdbc.url}</prop>        <prop key="username">${jdbc.username}</prop>        <prop key="password">${jdbc.password}</prop>      </props>    </property>  </bean>  <!--配置數(shù)據(jù)源二-->  <bean id="dataSourceTwo" parent="abstractXADataSource">    <property name="uniqueResourceName">      <value>dataSourceTwo</value>    </property>    <property name="xaProperties">      <props>        <prop key="url">${jdbc.two.url}</prop>        <prop key="username">${jdbc.two.username}</prop>        <prop key="password">${jdbc.two.password}</prop>      </props>    </property>  </bean>    <!--mybatis的相關(guān)配置-->  <bean id="sqlSessionFactoryOne" class="org.mybatis.spring.SqlSessionFactoryBean">    <property name="dataSource" ref="dataSourceOne"/>    <property name="mapperLocations" value="classpath*:mapping/ds1/*.xml"/>  </bean>    <bean id="sqlSessionFactoryTwo" class="org.mybatis.spring.SqlSessionFactoryBean">    <property name="dataSource" ref="dataSourceTwo"/>    <property name="mapperLocations" value="classpath*:mapping/ds2/*.xml"/>  </bean>    <!--配置mybatis映射文件自動掃描-->  <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">    <property name="basePackage" value="net.xiake6.dao.ds1"/>    <property name="sqlSessionFactoryBeanName" value="sqlSessionFactoryOne"/>  </bean>  <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">    <property name="basePackage" value="net.xiake6.dao.ds2"/>    <property name="sqlSessionFactoryBeanName" value="sqlSessionFactoryTwo"/>  </bean>  <!--配置分布式事務(wù)-->  <bean id="atomikosTransactionManager" class="com.atomikos.icatch.jta.UserTransactionManager" init-method="init" destroy-method="close">    <property name="forceShutdown" value="false"/>  </bean>  <bean id="atomikosUserTransaction" class="com.atomikos.icatch.jta.UserTransactionImp">    <property name="transactionTimeout" value="3000"/>  </bean>  <!--JTA事務(wù)管理器-->  <bean id="jtaTransactionManager" class="org.springframework.transaction.jta.JtaTransactionManager">    <property name="transactionManager">      <ref bean="atomikosTransactionManager"/>    </property>    <property name="userTransaction">      <ref bean="atomikosUserTransaction"/>    </property>    <property name="allowCustomIsolationLevels" value="true"/>  </bean>      <aop:config proxy-target-class="true">     <aop:advisor pointcut="execution(* *net.xiake6.service..*(..))" advice-ref="txAdvice" />   </aop:config>   <tx:advice id="txAdvice" transaction-manager="jtaTransactionManager">     <tx:attributes>       <tx:method name="insert*" propagation="REQUIRED" read-only="false" rollback-for="*Exception"/>      <tx:method name="add*" propagation="REQUIRED" read-only="false" rollback-for="*Exception" />       <tx:method name="save*" propagation="REQUIRED" read-only="false" rollback-for="*Exception" />        <tx:method name="delete*" propagation="REQUIRED" read-only="false" rollback-for="*Exception" />       <tx:method name="del*" propagation="REQUIRED" read-only="false" rollback-for="*Exception" />       <tx:method name="update*" propagation="REQUIRED" read-only="false" rollback-for="*Exception" />      <tx:method name="select*" propagation="REQUIRED" read-only="true" />      <tx:method name="query" propagation="REQUIRED" read-only="true" />    </tx:attributes>   </tx:advice>    <!-- 配置事務(wù)管理 -->  <tx:annotation-driven transaction-manager="jtaTransactionManager" /></beans>

jdbc.properties

#mysql 6.*以上jdbc.driverClassName = com.mysql.cj.jdbc.Driverjdbc.url = jdbc:mysql://127.0.0.1:3306/test?serverTimezone=UTC&useUnicode=true&characterEncoding=UTF-8&pinGlobalTxToPhysicalConnection=true&useSSL=falsejdbc.username =rootjdbc.password =rootjdbc.two.url = jdbc:mysql://127.0.0.1:3306/test?serverTimezone=UTC&useUnicode=true&characterEncoding=UTF-8&pinGlobalTxToPhysicalConnection=true&useSSL=falsejdbc.two.username =rootjdbc.two.password =root

jta.properties

com.atomikos.icatch.service=com.atomikos.icatch.standalone.UserTransactionServiceFactorycom.atomikos.icatch.console_file_name=tm.release.outcom.atomikos.icatch.log_base_name=tm.releaselogcom.atomikos.icatch.tm_unique_name=com.atomikos.spring.jdbc.tm.releasecom.atomikos.icatch.console_log_level=INFO

TestInsert.java

@ContextConfiguration(value = {"classpath:spring-application-context.xml"})@RunWith(SpringJUnit4ClassRunner.class)public class TestInsert { private Logger logger = LoggerFactory.getLogger(TestInsert.class); @Autowired private BatchInsertService batchInsertService; @Test public void insert(){  long startTime = System.currentTimeMillis(); User user = new User(); user.setName("User_"+(int)(Math.random()*100)); user.setAge((int)(Math.random()*100));  CustInfo info = new CustInfo(); info.setPhone("123456789"+(int)(Math.random()*100)); batchInsertService.insert(user,info);  long endTime = System.currentTimeMillis(); logger.info("共耗時:{}毫秒",endTime -startTime); }}

BatchInsertService.java

@Servicepublic class BatchInsertService { private Logger logger = LoggerFactory.getLogger(BatchInsertService.class); @Autowired private UserService userService; @Autowired private CustInfoService custInfoService; @Transactional(rollbackFor= {Exception.class,RuntimeException.class}) public void insert(User user,CustInfo custInfo) { int insertUser = userService.insert(user); logger.info("insertUser={}",insertUser); int insertCustInfo = custInfoService.insert(custInfo); logger.info("insertCustInfo={}",insertCustInfo); }}

UserService.java

@Servicepublic class UserService { @Autowired private UserMapper userMapper;  public int insert(User record) { int result = userMapper.insert(record); return result; } }

CustInfoService.java

@Servicepublic class CustInfoService { @Autowired private CustInfoMapper custInfoMapper; public int insert(CustInfo record) { int result = custInfoMapper.insert(record); long now = System.currentTimeMillis(); // 模擬一個異常 if (now % 2 == 0) {  throw new RuntimeException("CustInfoMapper throws test insert exception"); } return result; }}

看完上述內(nèi)容,你們對Spring中怎么利用atomikos+druid實現(xiàn)分布式事務(wù)有進(jìn)一步的了解嗎?如果還想了解更多知識或者相關(guān)內(nèi)容,請關(guān)注億速云行業(yè)資訊頻道,感謝大家的支持。

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI