atomikos的一些实践

本文就是记录自己的一次学习与测试,内容是atomikos实现分布式事务

学习了很多理论的东西,一些分布式事务、二次提交、三次提交、XA模式等等一些理论,很多都是看个新鲜,所以还是得动手实践,这样怕是能够更好得理解这些理论。

atomikos 是java平台提供的开源事务管理器

环境:spring boot 2.1.2  atomikos  jdbc

具体pom

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.1.2.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.cherish_lailai</groupId>
    <artifactId>atomikos-jta</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>atomikos-jta</name>
    <description>Demo project for Spring Boot</description>

    <properties>
        <java.version>1.8</java.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-jdbc</artifactId>
            <exclusions>
                <exclusion>
                    <groupId>org.apache.tomcat</groupId>
                    <artifactId>tomcat-jdbc</artifactId>
                </exclusion>
            </exclusions>
        </dependency>

        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.1.0</version>
        </dependency>

        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.0.8</version>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-jta-atomikos</artifactId>
        </dependency>

    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

三个配置

1、配置文件读取的java配置,两份分别为OrderDBConfig、UserDBConfig

2、数据源配置 DBConfig

package com.cherish_lailai.atomikosjta.config;

import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;

@Component
@ConfigurationProperties(prefix="mysql.datasource.order")
public class OrderDBConfig {
    private String url;
    private String username;
    private String password;
    private int minPoolSize;
    private int maxPoolSize;
    private int maxLifetime;
    private int borrowConnectionTimeout;
    private int loginTimeout;
    private int maintenanceInterval;
    private int maxIdleTime;
    public String getUrl() {
        return url;
    }
    public void setUrl(String url) {
        this.url = url;
    }
    public String getUsername() {
        return username;
    }
    public void setUsername(String username) {
        this.username = username;
    }
    public String getPassword() {
        return password;
    }
    public void setPassword(String password) {
        this.password = password;
    }
    public int getMinPoolSize() {
        return minPoolSize;
    }
    public void setMinPoolSize(int minPoolSize) {
        this.minPoolSize = minPoolSize;
    }
    public int getMaxPoolSize() {
        return maxPoolSize;
    }
    public void setMaxPoolSize(int maxPoolSize) {
        this.maxPoolSize = maxPoolSize;
    }
    public int getMaxLifetime() {
        return maxLifetime;
    }
    public void setMaxLifetime(int maxLifetime) {
        this.maxLifetime = maxLifetime;
    }
    public int getBorrowConnectionTimeout() {
        return borrowConnectionTimeout;
    }
    public void setBorrowConnectionTimeout(int borrowConnectionTimeout) {
        this.borrowConnectionTimeout = borrowConnectionTimeout;
    }
    public int getLoginTimeout() {
        return loginTimeout;
    }
    public void setLoginTimeout(int loginTimeout) {
        this.loginTimeout = loginTimeout;
    }
    public int getMaintenanceInterval() {
        return maintenanceInterval;
    }
    public void setMaintenanceInterval(int maintenanceInterval) {
        this.maintenanceInterval = maintenanceInterval;
    }
    public int getMaxIdleTime() {
        return maxIdleTime;
    }
    public void setMaxIdleTime(int maxIdleTime) {
        this.maxIdleTime = maxIdleTime;
    }
}
package com.cherish_lailai.atomikosjta.config;

import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;

@Component
@ConfigurationProperties(prefix="mysql.datasource.user")
public class UserDBConfig {
    private String url;
    private String username;
    private String password;
    private int minPoolSize;
    private int maxPoolSize;
    private int maxLifetime;
    private int borrowConnectionTimeout;
    private int loginTimeout;
    private int maintenanceInterval;
    private int maxIdleTime;
    public String getUrl() {
        return url;
    }
    public void setUrl(String url) {
        this.url = url;
    }
    public String getUsername() {
        return username;
    }
    public void setUsername(String username) {
        this.username = username;
    }
    public String getPassword() {
        return password;
    }
    public void setPassword(String password) {
        this.password = password;
    }
    public int getMinPoolSize() {
        return minPoolSize;
    }
    public void setMinPoolSize(int minPoolSize) {
        this.minPoolSize = minPoolSize;
    }
    public int getMaxPoolSize() {
        return maxPoolSize;
    }
    public void setMaxPoolSize(int maxPoolSize) {
        this.maxPoolSize = maxPoolSize;
    }
    public int getMaxLifetime() {
        return maxLifetime;
    }
    public void setMaxLifetime(int maxLifetime) {
        this.maxLifetime = maxLifetime;
    }
    public int getBorrowConnectionTimeout() {
        return borrowConnectionTimeout;
    }
    public void setBorrowConnectionTimeout(int borrowConnectionTimeout) {
        this.borrowConnectionTimeout = borrowConnectionTimeout;
    }
    public int getLoginTimeout() {
        return loginTimeout;
    }
    public void setLoginTimeout(int loginTimeout) {
        this.loginTimeout = loginTimeout;
    }
    public int getMaintenanceInterval() {
        return maintenanceInterval;
    }
    public void setMaintenanceInterval(int maintenanceInterval) {
        this.maintenanceInterval = maintenanceInterval;
    }
    public int getMaxIdleTime() {
        return maxIdleTime;
    }
    public void setMaxIdleTime(int maxIdleTime) {
        this.maxIdleTime = maxIdleTime;
    }
}
package com.cherish_lailai.atomikosjta.config;

import com.mysql.jdbc.jdbc2.optional.MysqlXADataSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.jta.atomikos.AtomikosDataSourceBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.core.JdbcTemplate;

import javax.sql.DataSource;
import java.sql.SQLException;

@Configuration
public class DBConfig {

    @Autowired
    private UserDBConfig userDBConfig;

    @Autowired OrderDBConfig orderDBConifg;

    @Bean(name = "userDatasource")
    public DataSource userDataSource() throws SQLException {
        MysqlXADataSource mysqlXADataSource=new MysqlXADataSource();
        mysqlXADataSource.setUrl(userDBConfig.getUrl());
        mysqlXADataSource.setPinGlobalTxToPhysicalConnection(true);
        mysqlXADataSource.setPassword(userDBConfig.getPassword());
        mysqlXADataSource.setUser(userDBConfig.getUsername());
        mysqlXADataSource.setPinGlobalTxToPhysicalConnection(true);

        AtomikosDataSourceBean atomikosDataSourceBean=new AtomikosDataSourceBean();
        atomikosDataSourceBean.setXaDataSource(mysqlXADataSource);
        atomikosDataSourceBean.setUniqueResourceName("userDatasource");

        atomikosDataSourceBean.setMinPoolSize(userDBConfig.getMinPoolSize());
        atomikosDataSourceBean.setMaxPoolSize(userDBConfig.getMaxPoolSize());
        atomikosDataSourceBean.setMaxLifetime(userDBConfig.getMaxLifetime());
        atomikosDataSourceBean.setBorrowConnectionTimeout(userDBConfig.getBorrowConnectionTimeout());
        atomikosDataSourceBean.setLoginTimeout(userDBConfig.getLoginTimeout());
        atomikosDataSourceBean.setMaintenanceInterval(userDBConfig.getMaintenanceInterval());
        atomikosDataSourceBean.setMaxIdleTime(userDBConfig.getMaxIdleTime());
        return atomikosDataSourceBean;
    }

    @Bean(name = "userJdbcTemplate")
    public JdbcTemplate userJdbcTemplate() throws SQLException {
        DataSource userDataSource = userDataSource();
        return  new JdbcTemplate(userDataSource);
    }

    @Bean(name = "orderDatasource")
    public DataSource orderDataSource() throws SQLException {
        MysqlXADataSource mysqlXADataSource=new MysqlXADataSource();
        mysqlXADataSource.setUrl(orderDBConifg.getUrl());
        mysqlXADataSource.setPinGlobalTxToPhysicalConnection(true);
        mysqlXADataSource.setPassword(orderDBConifg.getPassword());
        mysqlXADataSource.setUser(orderDBConifg.getUsername());
        mysqlXADataSource.setPinGlobalTxToPhysicalConnection(true);

        AtomikosDataSourceBean atomikosDataSourceBean=new AtomikosDataSourceBean();
        atomikosDataSourceBean.setXaDataSource(mysqlXADataSource);
        atomikosDataSourceBean.setUniqueResourceName("orderDatasource");

        atomikosDataSourceBean.setMinPoolSize(orderDBConifg.getMinPoolSize());
        atomikosDataSourceBean.setMaxPoolSize(orderDBConifg.getMaxPoolSize());
        atomikosDataSourceBean.setMaxLifetime(orderDBConifg.getMaxLifetime());
        atomikosDataSourceBean.setBorrowConnectionTimeout(orderDBConifg.getBorrowConnectionTimeout());
        atomikosDataSourceBean.setLoginTimeout(orderDBConifg.getLoginTimeout());
        atomikosDataSourceBean.setMaintenanceInterval(orderDBConifg.getMaintenanceInterval());
        atomikosDataSourceBean.setMaxIdleTime(orderDBConifg.getMaxIdleTime());
        return atomikosDataSourceBean;
    }

    @Bean(name = "orderJdbcTemplate")
    public JdbcTemplate orderJdbcTemplate() throws SQLException {
        DataSource orderDataSource = orderDataSource();
        return  new JdbcTemplate(orderDataSource);
    }


}

简单得Dao

package com.cherish_lailai.atomikosjta.dao;

import com.cherish_lailai.atomikosjta.entity.Order;
import com.cherish_lailai.atomikosjta.entity.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.stereotype.Repository;

import javax.transaction.Transactional;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.List;

@Repository
public class OrderRepository {
    @Autowired
    @Qualifier("orderJdbcTemplate")
    private JdbcTemplate orderJdbcTemplate;


    //    查询所有的Order
    @Transactional
    public List<Order> findAllOrder() {
        List<Order> orderList = orderJdbcTemplate.query("select * from orderTable",new OrderRowMapper());
        return orderList;
    }

//    更新所有订单的的oname
    public void update(final Order order) {
        orderJdbcTemplate.update(
                "update orderTable set oname=?",
                new Object[]{order.getOname()});
    }

//    订单查询RowMapper
    class OrderRowMapper implements RowMapper<Order> {
        @Override
        public Order mapRow(ResultSet rs, int rowNum) throws SQLException {
            Order order = new Order();
            order.setId(rs.getInt("id"));
            order.setOname(rs.getString("oname"));
            return order;
        }
    }
}
package com.cherish_lailai.atomikosjta.dao;

import com.cherish_lailai.atomikosjta.entity.Order;
import com.cherish_lailai.atomikosjta.entity.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.stereotype.Repository;

import javax.transaction.Transactional;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.List;

@Repository
public class UserRepository {

    @Autowired
    @Qualifier("userJdbcTemplate")
    private JdbcTemplate userJdbcTemplate;



    //    查询所有的用户
   @Transactional
    public List<User> findAllUser() {
       List<User> userList = userJdbcTemplate.query("select * from userTable", new UserRowMapper());
       return userList;
    }

//      更新所有User的的uname
    public void update(final User user) {
        userJdbcTemplate.update(
                "update userTable set uname=?",
                new Object[]{user.getUname()});
    }

//     用户查询RowMapper
    class UserRowMapper implements RowMapper<User> {
        @Override
        public User mapRow(ResultSet rs, int rowNum) throws SQLException {
            User user = new User();
            user.setId(rs.getInt("id"));
            user.setUname(rs.getString("uname"));
            return user;
        }
    }

}

实体没啥就不贴了

public class Order {
    private Integer id;
    private String oname;
public class User {
    private Integer id;
    private String uname;

配置文件

application.properties

#user
mysql.datasource.user.url=jdbc:mysql://localhost:3306/userjta?useUnicode=true&characterEncoding=utf8
mysql.datasource.user.username=root
mysql.datasource.user.password=admin
mysql.datasource.user.minPoolSize=3
mysql.datasource.user.maxPoolSize=25
mysql.datasource.user.maxLifetime=20000
mysql.datasource.user.borrowConnectionTimeout=30
mysql.datasource.user.loginTimeout=30
mysql.datasource.user.maintenanceInterval=60
mysql.datasource.user.maxIdleTime=60
#order
mysql.datasource.order.url=jdbc:mysql://localhost:3306/orderjta?useUnicode=true&characterEncoding=utf8
mysql.datasource.order.username=root
mysql.datasource.order.password=admin
mysql.datasource.order.minPoolSize=3
mysql.datasource.order.maxPoolSize=25
mysql.datasource.order.maxLifetime=20000
mysql.datasource.order.borrowConnectionTimeout=30
mysql.datasource.order.loginTimeout=30
mysql.datasource.order.maintenanceInterval=60
mysql.datasource.order.maxIdleTime=60

测试代码

这里记录下(错误),下面的单元测试时有点问题的,我写完后总觉得不对劲,印象中单元测试的事务默认是会回滚的(具体的也还没去实践,不确定),担心测试结果会影响我的判断,所有如下才是正确的单元测试

@Autowired
private TestService testService;
@Test
public void testTx04(){
        testService.test();
}
package com.cherish_lailai.atomikosjta.Server;

import com.cherish_lailai.atomikosjta.dao.OrderRepository;
import com.cherish_lailai.atomikosjta.dao.UserRepository;
import com.cherish_lailai.atomikosjta.entity.Order;
import com.cherish_lailai.atomikosjta.entity.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.transaction.Transactional;

@Component
@Transactional
public class TestService {

    @Autowired
    private UserRepository userRepository;
    @Autowired
    private OrderRepository orderRepository;

    public void test(){
        User user = new User();
        user.setUname("uuuuu");
        userRepository.update(user);

//        int tmp= 1/0;

        Order order = new Order();
        order.setOname("ooooo");
        orderRepository.update(order);
    }

}

下面是原先错误的单元测试,留着以后看看,长个记性

package com.cherish_lailai.atomikosjta;

import com.cherish_lailai.atomikosjta.dao.OrderRepository;
import com.cherish_lailai.atomikosjta.dao.UserRepository;
import com.cherish_lailai.atomikosjta.entity.Order;
import com.cherish_lailai.atomikosjta.entity.User;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.internal.matchers.Or;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

import javax.sql.DataSource;
import javax.transaction.Transactional;
import java.util.List;

@RunWith(SpringRunner.class)
@SpringBootTest
public class TestDataSource {
    @Autowired
    private DataSource userDatasource;
    @Autowired
    private DataSource orderDatasource;
    @Test
    public void testDB(){
        System.out.println(userDatasource);
        System.out.println(orderDatasource);
    }
//      输出
//      AtomikosDataSoureBean 'userDatasource'
//      AtomikosDataSoureBean 'orderDatasource'



    @Autowired
    private UserRepository userRepository;
    @Autowired
    private OrderRepository orderRepository;

    @Test
    public void testDao(){
        List<User> allUser = userRepository.findAllUser();
        System.out.println(allUser);
        List<Order> allOrder = orderRepository.findAllOrder();
        System.out.println(allOrder);
    }
//    输出
//      [User{id=1, uname='user1'}]
//      [Order{id=1, oname='order1'}]


//开始测试事务

//    测试01
//    未使用事务,也跨数据库操作
    @Test
    public void testTx01(){
        User user = new User();
        user.setUname("beforException");
        userRepository.update(user);
        int tmp= 1/0;
        user.setUname("afterException");
        userRepository.update(user);
    }
//    未开始事务
//    数据库查看结果 id=1 uname=beforException
//    结论未执行事务

//    测试02
//    开始事务
    @Test
    @Transactional
    public void testTx02(){
        User user = new User();
        user.setUname("beforException");
        userRepository.update(user);
        int tmp= 1/0;
        user.setUname("afterException");
        userRepository.update(user);
    }
//     开启了事务
//    数据库查看结果 还是id=1 uname=user01
//    结论userjta数据库中执行了事务

//    测试03
//    跨数据库操作(分布式事务)

    @Test
    @Transactional
    public void testTx03(){
        User user = new User();
        user.setUname("uuuuu");
        userRepository.update(user);

        int tmp= 1/0;

        Order order = new Order();
        order.setOname("ooooo");
        orderRepository.update(order);

    }
//     开启了事务
//    数据库查看结果  user还是id=1 uname=user01
//                    order还是id=1 oname=order01
//    跨数据库操作处于同一个事务中

}

发现多了个文件

清空该文件,再次执行第三个测试(跨数据库操作user与order),查看文件内容

{"id":"192.168.101.1.tm154814032792000001","wasCommitted":false,"participants":[{"uri":"192.168.101.1.tm1","state":"TERMINATED","expires":1548140338485,"resourceName":"userDatasource"}]}

发现大概意思就是说我的user操作没有被提交

总之好像是测出了那个意思,有错望指正,谢谢!

PS:都在使用云笔记,好久没写都快忘了自己也是小编,嘿嘿~

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值