基于spring+mybatis+atomikos+jta实现分布式事务

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了基于spring+mybatis+atomikos+jta实现分布式事务相关的知识,希望对你有一定的参考价值。

本文介绍基于spring+mybatis+atomikos+jta实现分布式事务,分布式事务的实现方式基于配置文件,不同的mybatis mapper绑定在不同的数据源上,通过atomikos可实现分布式事务一致性。

版本:spring-3.2.9.RELEASE、mybatis-3.4.4、atomikos-4.0.5、jdk1.8

1,maven配置文件pom.xml如下:

    <!-- test -->
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.12</version>
        <scope>test</scope>
        <exclusions>
            <exclusion>
                <artifactId>hamcrest-core</artifactId>
                <groupId>org.hamcrest</groupId>
            </exclusion>
        </exclusions>
    </dependency>
    <dependency>
        <groupId>org.hamcrest</groupId>
        <artifactId>hamcrest-all</artifactId>
        <version>1.3</version>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>org.mockito</groupId>
        <artifactId>mockito-core</artifactId>
        <version>1.9.5</version>
        <scope>test</scope>
        <exclusions>
            <exclusion>
                <artifactId>hamcrest-core</artifactId>
                <groupId>org.hamcrest</groupId>
            </exclusion>
        </exclusions>
    </dependency>
    <dependency>
        <groupId>com.jayway.jsonpath</groupId>
        <artifactId>json-path</artifactId>
        <version>0.8.1</version>
        <scope>test</scope>
    </dependency>
    <!-- spring -->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-aop</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-context</artifactId>
        <version>${spring.version}</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-core</artifactId>
        <version>${spring.version}</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-expression</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-webmvc</artifactId>
        <version>${spring.version}</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-webmvc-portlet</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-jdbc</artifactId>
        <version>${spring.version}</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-test</artifactId>
        <version>3.2.18.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-struts</artifactId>
        <version>${spring.version}</version>
    </dependency>
    <!-- mybatis -->
    <dependency>
        <groupId>org.mybatis</groupId>
        <artifactId>mybatis</artifactId>
        <version>3.4.4</version>
    </dependency>
    <dependency>
        <groupId>org.mybatis</groupId>
        <artifactId>mybatis-spring</artifactId>
        <version>1.3.1</version>
    </dependency>

    <!-- mysql-jdbc -->
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>5.1.27</version>
    </dependency>

    <!-- atomikos begin -->
    <dependency>
        <groupId>com.atomikos</groupId>
        <artifactId>transactions-jdbc</artifactId>
        <version>4.0.5</version>
    </dependency>
    <!-- atomikos end -->

    <!-- jta begig -->
    <dependency>
        <groupId>javax.transaction</groupId>
        <artifactId>jta</artifactId>
        <version>1.1</version>
    </dependency>
    <!-- jta end -->
    <!-- jackson -->
    <dependency>
        <groupId>org.codehaus.jackson</groupId>
        <artifactId>jackson-mapper-asl</artifactId>
        <version>1.9.13</version>
    </dependency>
    <dependency>
        <groupId>org.codehaus.jackson</groupId>
        <artifactId>jackson-core-asl</artifactId>
        <version>1.9.13</version>
    </dependency>
    <!-- jackson end -->
    <dependency>
        <groupId>org.aspectj</groupId>
        <artifactId>aspectjweaver</artifactId>
        <version>1.8.13</version>
    </dependency>

    <dependency>
        <groupId>log4j</groupId>
        <artifactId>log4j</artifactId>
        <version>1.2.16</version>
    </dependency>
    <dependency>
        <groupId>javax.servlet</groupId>
        <artifactId>servlet-api</artifactId>
        <version>2.5</version>
        <scope>provided</scope>
    </dependency>

2,数据库连接配置文件:jdbc.properties

jdbc.xaDataSourceClassName=com.mysql.jdbc.jdbc2.optional.MysqlXADataSource
validationQuery=select 1

ds1.jdbc.url=jdbc:mysql://xx.xx.xx.xx:3306/test1?characterEncoding=UTF-8
ds1.jdbc.username=xxxx
ds1.jdbc.password=xxxx

ds2.jdbc.url=jdbc:mysql://xx.xx.xx.xx:3306/test2?characterEncoding=UTF-8
ds2.jdbc.username=xxxx
ds2.jdbc.password=xxxx

3,atomikos配置文件:jta.properties

com.atomikos.icatch.service=com.atomikos.icatch.standalone.UserTransactionServiceFactory
com.atomikos.icatch.console_file_name=tm.release.out
com.atomikos.icatch.log_base_name=tm.releaselog
com.atomikos.icatch.tm_unique_name=com.atomikos.spring.jdbc.tm.release
com.atomikos.icatch.console_log_level=INFO

4,spring-datasource-jta.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">;
<beans>
<bean id="propertyConfigurer"
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="locations">
<list>
<value>classpath*:jdbc.properties</value>
</list>
</property>
</bean>
<bean id="txManager"
class="org.springframework.transaction.jta.JtaTransactionManager">
<property name="transactionManager">
<bean class="com.atomikos.icatch.jta.UserTransactionManager"
init-method="init" destroy-method="close">
<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>
</bean>

${ds1.jdbc.url} ${ds1.jdbc.username} ${ds1.jdbc.password} ${ds2.jdbc.url} ${ds2.jdbc.username} ${ds2.jdbc.password} true
## 5,spring-mybatis.xml classpath:mybatis/model/*.xml classpath:mybatis/model2/*.xml ## 6,编写mybatis.model代码,HelloDO.java、HelloMapper.java、HelloMapper.xml HelloDO.java package mybatis.model; public class HelloDO { private Long id; private String name; public Long getId() { return id; } public void setId(Long id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } } HelloMapper.java package mybatis.model; import org.springframework.stereotype.Repository; @Repository(value="helloMapper") public interface HelloMapper { public void insert(HelloDO hello); } HelloMapper.xml insert into HELLO(ID,NAME) values(#{id},#{name}) ## 7,编写mybatis.model2代码,HelloDO.java、HelloMapper.java、HelloMapper.xml HelloDO.java package mybatis.model2; public class HelloDO { private Long id; private String name; public Long getId() { return id; } public void setId(Long id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } } HelloMapper.java package mybatis.model2; import org.springframework.stereotype.Repository; @Repository(value="helloMapper2") public interface HelloMapper { public void insert(HelloDO hello); } HelloMapper.xml insert into HELLO(ID,NAME) values(#{id},#{name}) ## 8,编写service类:mybatis.service.HelloWorldService.java package mybatis.service; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import mybatis.model.HelloDO; import mybatis.model.HelloMapper; @Service("helloWorldService") public class HelloWorldService { @Autowired private HelloMapper helloMapper; @Autowired private mybatis.model2.HelloMapper helloMapper2; public void addHello(HelloDO helloDO) { // TODO Auto-generated method stub helloMapper.insert(helloDO); } public void addHello2(mybatis.model2.HelloDO helloDO) { helloMapper2.insert(helloDO); } } ## 9,编写controller类:mybatis.controler.HelloWorldController.java package mybatis.controller; import org.springframework.beans.BeanUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.springframework.transaction.annotation.Transactional; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.ResponseBody; import mybatis.model.HelloDO; import mybatis.service.HelloWorldService; @Controller(value = "helloWorldController") @RequestMapping(value="/hello") public class HelloWorldControler { @Autowired private HelloWorldService helloWorldService; @Transactional @RequestMapping(value="/create", method = RequestMethod.POST, consumes = {"text/plain", "application/*"}) public @ResponseBody long createHello(@RequestBody HelloDO helloDO) { helloWorldService.addHello(helloDO); mybatis.model2.HelloDO helloDO2 = new mybatis.model2.HelloDO(); BeanUtils.copyProperties(helloDO, helloDO2); helloWorldService.addHello2(helloDO2); return helloDO.getId(); } } ## 10,编写测试类:HelloWorldControllerTest.java package mybatis.controller; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; import org.codehaus.jackson.map.ObjectMapper; import org.codehaus.jackson.map.ObjectWriter; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.MediaType; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import org.springframework.test.context.web.WebAppConfiguration; import org.springframework.test.web.servlet.MockMvc; import org.springframework.test.web.servlet.setup.MockMvcBuilders; import org.springframework.web.context.WebApplicationContext; import mybatis.model.HelloDO; @RunWith(SpringJUnit4ClassRunner.class) @WebAppConfiguration @ContextConfiguration({ "classpath:spring-datasource-jta.xml", "classpath:spring-mybatis.xml" }) public class HelloWorldControlerTest { @Autowired private WebApplicationContext context; private MockMvc mocMvc; @Before public void setUp() throws Exception { mocMvc = MockMvcBuilders.webAppContextSetup(context).build(); } @Test public void test() throws Exception { String data = "{\"id\":1,\"name\":\"abc\"}"; HelloDO hello = new HelloDO(); hello.setId(1L); hello.setName("abc"); ObjectMapper mapper = new ObjectMapper(); ObjectWriter ow = mapper.writer().withDefaultPrettyPrinter(); java.lang.String requestJson = ow.writeValueAsString(hello); mocMvc.perform(post("/hello/create").contentType(MediaType.APPLICATION_JSON).content(data)).andExpect(status().isOk()); } } ## 11,至此,基于配置文件实现分布式事务一致性已经实现,下一篇文件将介绍通过代码来动态切换数据源,并保持数据库事务一致性。

以上是关于基于spring+mybatis+atomikos+jta实现分布式事务的主要内容,如果未能解决你的问题,请参考以下文章

spring+mybatis+tkmapper+atomikos实现分布式事务-动态切换数据源

请教mybatis+spring+atomikos的整合问题

spring+mybatis+Atomikos JTA事务配置说明

Spring事务隔离级别与传播机制,spring+mybatis+atomikos实现分布式事务管理

spring事务隔离级别传播行为以及spring+mybatis+atomikos实现分布式事务管理

Spring事务隔离级别与传播机制,spring+mybatis+atomikos实现分布式事务管理