• springboot+druid+mybatis+mysql+多数据源事务管理


    springboot+druid+mybatis+mysql+多数据源事务管理

    分布式事务在java中的解决方案就是JTA(即Java Transaction API);springboot官方提供了 Atomikos or Bitronix的解决思路;其实,大多数情况下很多公司是使用消息队列的方式实现分布式事务。这里分享的是Atomikos 的简单事务管理。

    项目依赖

    pom.xml中添加atomikos的springboot相关依赖:

    <!--分布式事务管理器-->
         <dependency>
             <groupId>org.springframework.boot</groupId>
             <artifactId>spring-boot-starter-jta-atomikos</artifactId>
         </dependency>
         <dependency>
             <groupId>mysql</groupId>
             <artifactId>mysql-connector-java</artifactId>
             <!--这里最好要5.1.47之后的版本-->
             <version>5.1.47</version>
         </dependency>
    

    application.properties配置文件中数据库相关信息:

    #数据库1
    spring.datasource.druid.one.url=jdbc:mysql://localhost:3306/test01?useUnicode=true&characterEncoding=utf-8
    spring.datasource.druid.one.username=root
    spring.datasource.druid.one.password=123456
    
    #数据库2
    spring.datasource.druid.two.url=jdbc:mysql://localhost:3306/test02?useUnicode=true&characterEncoding=utf-8
    spring.datasource.druid.two.username=root
    spring.datasource.druid.two.password=123456
    

    创建两个java配置类,分别读取上面的两个数据库相关信息:

    @ConfigurationProperties(prefix = "spring.datasource.druid.one")
    public class DsOneProperties {
        private String username;
        private String password;
        private String url;
    	//这里省掉Set和get方法
    }
    
    @ConfigurationProperties(prefix = "spring.datasource.druid.two")
    public class DsTwoProperties {
        private String username;
        private String password;
        private String url;
        //这里省掉Set和get方法
    }
    

    在SpringBoot项目启动类加上注解,启动时,就加载相关信息

    @EnableConfigurationProperties(value = {DsOneProperties.class, DsTwoProperties.class})
    

    创建主数据库配置类MyBatisConfigOne :

    @Configuration//声明该类是一个配置类
    @MapperScan(basePackages = "com.lwh.mybatistest.mapper", sqlSessionFactoryRef = "sqlSessionFactory1", sqlSessionTemplateRef = "sqlSessionTemplate1")
    //扫描的包是com.lwh.mybatistest.mapper
    public class MyBatisConfigOne {
        // 配置主数据源
        @Primary
        @Bean
        public DataSource dsOne(DsOneProperties dsOneProperties) throws SQLException {
            //配置XA协议数据源,从配置文件中读取相应属性
            MysqlXADataSource mysqlXaDataSource = new MysqlXADataSource();
            mysqlXaDataSource.setUrl(dsOneProperties.getUrl());
            mysqlXaDataSource.setPassword(dsOneProperties.getPassword());
            mysqlXaDataSource.setUser(dsOneProperties.getUsername());
            //将本地事务注册到Atomikos全局事务
            AtomikosDataSourceBean xaDataSource = new AtomikosDataSourceBean();
            xaDataSource.setXaDataSource(mysqlXaDataSource);
            xaDataSource.setUniqueResourceName("dsOne");
            return xaDataSource;
        }
    
        @Primary
        @Bean(name = "sqlSessionFactory1")
        public SqlSessionFactory SqlSessionFactory1(@Qualifier("dsOne") DataSource dataSource)
                throws Exception {
            SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
            bean.setDataSource(dataSource);
            return bean.getObject();
        }
    
        @Primary
        @Bean(name = "sqlSessionTemplate1")
        public SqlSessionTemplate SqlSessionTemplate1(
                @Qualifier("sqlSessionFactory1") SqlSessionFactory sqlSessionFactory) throws Exception {
            return new SqlSessionTemplate(sqlSessionFactory);
        }
    }
    

    依照上面主数据库配置类,创建从数据库配置类:

    @Configuration
    @MapperScan(basePackages = "com.lwh.mybatistest.mapper2", sqlSessionFactoryRef = "sqlSessionFactory2", sqlSessionTemplateRef = "sqlSessionTemplate2")
    public class MyBatisConfigTwo {
        @Bean
        public DataSource dsTwo(DsTwoProperties dsTwoProperties) throws SQLException {
            //配置从数据源
            //配置XA协议数据源,从配置文件中读取相应属性
            MysqlXADataSource mysqlXaDataSource = new MysqlXADataSource();
            mysqlXaDataSource.setUrl(dsTwoProperties.getUrl());
            mysqlXaDataSource.setPassword(dsTwoProperties.getPassword());
            mysqlXaDataSource.setUser(dsTwoProperties.getUsername());
            //将本地事务注册到Atomikos全局事务
            AtomikosDataSourceBean xaDataSource = new AtomikosDataSourceBean();
            xaDataSource.setXaDataSource(mysqlXaDataSource);
            xaDataSource.setUniqueResourceName("dsTwo");
            return xaDataSource;
        }
    
        @Bean(name = "sqlSessionFactory2")
        public SqlSessionFactory SqlSessionFactory2(@Qualifier("dsTwo") DataSource dataSource)
                throws Exception {
            SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
            bean.setDataSource(dataSource);
            return bean.getObject();
        }
    
    
        @Bean(name = "sqlSessionTemplate2")
        public SqlSessionTemplate SqlSessionTemplate2(
                @Qualifier("sqlSessionFactory2") SqlSessionFactory sqlSessionFactory) throws Exception {
            return new SqlSessionTemplate(sqlSessionFactory);
        }
    }
    

    创建一个简单的controller测试类:

    @RestController
    @RequestMapping("/book")
    public class BookController {
        @Autowired
        BookService bookService;
    
        @Autowired
        BookService2 bookService2;
    
        @GetMapping("/add1")
        @Transactional
        public String addBook() {
            Book book = new Book();
            book.setBookname("测试");
            book.setAuthor("test:01");
            System.out.println("数据库1:>>>>");
            bookService.addBook(book);
            System.out.println("数据库2:>>>>");
            bookService2.addBook(book);
            return "测试add1操作成功!";
        }
        
        @GetMapping("/add2")
        @Transactional
        public String addBook2() {
            Book book = new Book();
            book.setBookname("测试add2");
            book.setAuthor("test:01");
            System.out.println("数据库1:>>>>");
            bookService.addBook(book);
            int a = 10 / 0;
            System.out.println("数据库2:>>>>");
            bookService2.addBook(book);
            return "测试add2操作成功!";
        }
    }
    

    Service类,就是简单的插入方法,调用mapper:

    @Service
    public class BookService {
    
        @Autowired
        BookMapper bookMapper;
    
        public void addBook(Book book) {
            bookMapper.insertSelective(book);
        }
    }
    

    springboot默认有事务管理器,所以这里没有配置,使用默认的即可,如果有特别需求,可以自行创建自己的事务管理器。
    最简单的atomikos插件的使用就配置完了,配置信息相对简单,想深入学习的同学,可以参考官方的文档。

    分布式事务有多种主流形态,包括:
    基于消息实现的分布式事务
    基于补偿实现的分布式事务(gts/seata自动补偿的形式)
    基于TCC实现的分布式事务
    基于SAGA实现的分布式事务
    基于2PC实现的分布式事务
    之所以有这么多形态,是因为任何事情都没有银弹,只有最合适当前场景的解决方案。

  • 相关阅读:
    关于本Blog无法进行评论问题的说明
    Apusic Operamasks例子部署过程
    JVM启动参数(转)
    20070724中间件产品培训方式总结
    写Blog的意义
    磁碟機讀取光碟片時遇故障7/9
    .aspx沒有語言擴充功能8/14
    水晶報表公式的dateadd及cstr應用7/11
    中毒了:Trojar6/26
    學位英語考試通過啦8/28
  • 原文地址:https://www.cnblogs.com/lwhsummer/p/11241774.html
Copyright © 2020-2023  润新知