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


    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.最终一直性方案

  • 相关阅读:
    C#中使用$"{}"替换string.Format()
    js==>id-pid转children【】树结构数据
    React使用模板
    C#--fetch配置使用
    ...扩展运算符解释
    java之死锁
    Stream流
    lambda 之 forEach( ->{} )
    java基础之递归(九九乘法表)
    java读取 .xlsx格式文件转成list
  • 原文地址:https://www.cnblogs.com/AnKangwenqiang/p/16189559.html
Copyright © 2020-2023  润新知