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實現的分布式事務
之所以有這么多形態,是因為任何事情都沒有銀彈,只有最合適當前場景的解決方案。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM