转载

springboot分布式事务atomikos

atomikos应用场景:单应用多数据源

引入依赖

<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-jta-atomikos</artifactId>
</dependency>
<dependency>
	<groupId>org.mybatis.spring.boot</groupId>
	<artifactId>mybatis-spring-boot-starter</artifactId>
	<version>2.0.1</version>
</dependency>
<!-- 这里不使用自动配置,所以不引入starter -->
<dependency>
	<groupId>com.alibaba</groupId>
	<artifactId>druid</artifactId>
	<version>1.1.14</version>
</dependency>

<dependency>
	<groupId>mysql</groupId>
	<artifactId>mysql-connector-java</artifactId>
	<scope>runtime</scope>
</dependency>

<dependency>
	<groupId>org.projectlombok</groupId>
	<artifactId>lombok</artifactId>
	<optional>true</optional>
</dependency>
<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-test</artifactId>
	<scope>test</scope>
</dependency>
复制代码

修改配置文件

spring:
  datasource:
    #使用druid连接池
    druid:
      #数据源1的名称
      one:
        driver-class-name: com.mysql.jdbc.Driver
        url: jdbc:mysql://192.168.211.128:3306/test?useUnicode=true&characterEncoding=UTF-8&useSSL=false
        username: root
        password: root
      #数据源2的名称
      two:
        driver-class-name: com.mysql.jdbc.Driver
        url: jdbc:mysql://192.168.211.129:3306/test?useUnicode=true&characterEncoding=UTF-8&useSSL=false
        username: root
        password: root
复制代码

配置数据源

只需要配置数据源即可,全局事务管理器(JtaTransactionManager)由spring自动配置

@Configuration
public class DataSourceConfig {

    /**
     * 创建Druid的XA连接池
     * @return
     */
    @Bean
    @ConfigurationProperties("spring.datasource.druid.one")
    public XADataSource druidXADataSource1(){
        return new DruidXADataSource();
    }

    /**
     * 创建Atomikos数据源
     * 注解@DependsOn("druidXADataSource1"),在名为druidXADataSource1的bean实例化后加载当前bean
     * @param xaDataSource
     * @return
     */
    @Bean
    @DependsOn("druidXADataSource1")
    @Primary
    public DataSource dataSource1(@Qualifier("druidXADataSource1") XADataSource xaDataSource) {
        //这里的AtomikosDataSourceBean使用的是spring提供的
        AtomikosDataSourceBean dataSource = new AtomikosDataSourceBean();
        dataSource.setXaDataSource(xaDataSource);
        return dataSource;
    }


    @Bean
    @ConfigurationProperties("spring.datasource.druid.two")
    public XADataSource druidXADataSource2(){
        return new DruidXADataSource();
    }

    @Bean
    @DependsOn("druidXADataSource2")
    public DataSource dataSource2(@Qualifier("druidXADataSource2") XADataSource xaDataSource) {
        AtomikosDataSourceBean dataSource = new AtomikosDataSourceBean();
        dataSource.setXaDataSource(xaDataSource);
        return dataSource;
    }
}
复制代码

配置mybatis

如果使用其他的orm框架,自行配置。

数据源2的mybatis配置和下面代码相似,去除@Primary注解,修改配置属性即可。

@Configuration
//指定扫描的dao包和SqlSession实例
@MapperScan(basePackages = "demo.springboot.atomikos.dao1", sqlSessionTemplateRef = "sessionTemplate1")
public class Mybatis1Config {

    /**
     * SqlSessionFactory
     *
     * @param dataSource
     * @return
     * @throws Exception
     */
    @Bean
    @Primary
    public SqlSessionFactory sqlSessionFactory1(@Qualifier("dataSource1") DataSource dataSource) throws Exception {
        SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
        bean.setDataSource(dataSource);
        //mapper文件位置
//        bean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath:mapper/one/*.xml"));
        return bean.getObject();
    }

    /**
     * SqlSession实例
     *
     * @param sqlSessionFactory
     * @return
     */
    @Bean
    @Primary
    public SqlSessionTemplate sessionTemplate1(@Qualifier("sqlSessionFactory1") SqlSessionFactory sqlSessionFactory) {
        return new SqlSessionTemplate(sqlSessionFactory);
    }
}
复制代码

DAO

public interface UserDAO1 {

    @Update("update user set name = #{name} where id = #{id}")
    int updateById(@Param("name")String name, @Param("id")Long id);
}

public interface UserDAO2 {

    @Update("update user set name = #{name} where id = #{id}")
    int updateById(@Param("name")String name, @Param("id")Long id);
}
复制代码

service

@Service
public class TestService {
    @Autowired
    private UserDAO1 userDAO1;
    @Autowired
    private UserDAO2 userDAO2;

 	/**
     * 在需要事务的方法加上@Transactional注解即可
     */
    @Transactional
    public void test(){
        userDAO1.updateById("haha", 1L);
        userDAO2.updateById("hehe", 2L);
        //模拟异常
        int a = 1/0;
    }
}
复制代码

测试

@RunWith(SpringRunner.class)
@SpringBootTest
public class AtomikosApplicationTests {

    @Autowired
    private TestService testService;

    @Test
    public void test() {
        testService.test();
    }

}
复制代码

数据源1中的User{"id":1,"name":"张三"}

数据源2中的User{"id":2,name:"李四"}

运行测试出现异常后,两个数据库都回滚了,数据未改变

项目路径

作者博客

作者公众号 springboot分布式事务atomikos

原文  https://juejin.im/post/5e676c30518825490b6492ca
正文到此结束
Loading...