分布式事务一站式解决方案

1.二阶段提交

springboot分布式事务atomikos

2020年03月11日 01:42 ·  阅读 967

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:"李四"}
运行测试出现异常后,两个数据库都回滚了,数据未改变

2.TCC补偿方式

 

3.最终一直性方案

posted on   AnkangWenqiang  阅读(26)  评论(0编辑  收藏  举报

相关博文:
阅读排行:
· 25岁的心里话
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 零经验选手,Compose 一天开发一款小游戏!
· 通过 API 将Deepseek响应流式内容输出到前端
· AI Agent开发,如何调用三方的API Function,是通过提示词来发起调用的吗
< 2025年3月 >
23 24 25 26 27 28 1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31 1 2 3 4 5

导航

统计

点击右上角即可分享
微信分享提示