spring-boot入门(七)atomikos+druid+多数据源下的分布式事务配置

spring-boot入门(七)atomikos+druid+多数据源下的分布式事务配置

本章内容是基于spring-boot入门(六)多数据源的基础之上进行的,如果还不了解多数据源怎么配置,请参考上一章节的内容。在上一章节的末尾我们遗留了一个问题:多数据源下的分布式事务问题。在分布式事务下我们需要使用JTA(Java Transaction API)事务来处理事务,保证事务的强一致性,即要成功都成功,一个失败全部回滚。Atomikos 是一个为Java平台提供增值服务的并且开源类事务管理器,本章我们将使用Atomikos 来解决分布式事务问题。

1. 配置atomikos

JTA事务的配置需要配置:XA数据源和JTA事务管理器

1.1 引入atomikos依赖

spring boot集成atomikos,只需添加一下依赖即可

        <dependency>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-starter-jta-atomikosartifactId>
        dependency>

1.2 自定义atomikos相关属性(自动注入JTA事务管理器)

如果不自定义相关属性,那么spring boot 会初始化默认的atomikos配置,可看org.springframework.boot.autoconfigure.transaction.jta.AtomikosJtaConfiguration是如何初始化默认的配置。当然也可以自定义atomikos,通过该配置spring boot会启用atomikos实现的JTA事务管理器。

spring:
  jta:
    atomikos:
      properties:
        max-actives: 50
        max-timeout: 300000
        default-jta-timeout: 10000
        enable-logging: true

上面是atomikos的一个配置示例。更多可查看org.springframework.boot.jta.atomikos.AtomikosProperties。

1.3 配置XA数据源

   @Bean
    @Primary
    @ConfigurationProperties(prefix = "boc.datasource")
    public DataSource bocDataSource(@Qualifier("bocDataSourceProperties") DataSourceProperties dataSourceProperties) throws SQLException {
        DruidXADataSource druidXADataSource = new DruidXADataSource();
        InitDruidDataSource(druidXADataSource, dataSourceProperties);

        AtomikosDataSourceBean atomikosDataSource = new AtomikosDataSourceBean();
        atomikosDataSource.setUniqueResourceName("bocDataSource");
        atomikosDataSource.setXaDataSource(druidXADataSource);
        atomikosDataSource.setTestQuery("SELECT 1");
        return atomikosDataSource;
    }

    @Bean
    @ConfigurationProperties(prefix = "ccb.datasource")
    public DataSource ccbDataSource(@Qualifier("ccbDataSourceProperties") DataSourceProperties dataSourceProperties) throws SQLException {
        DruidXADataSource druidXADataSource = new DruidXADataSource();
        InitDruidDataSource(druidXADataSource, dataSourceProperties);

        //也可以使用mysql默认的xa数据源
        //MysqlXADataSource mysqlXADataSource = new MysqlXADataSource();
        //mysqlXADataSource.setUrl(dataSourceProperties.getUrl());
        //mysqlXADataSource.setUser(dataSourceProperties.getUsername());
        //mysqlXADataSource.setPassword(dataSourceProperties.getPassword());

        AtomikosDataSourceBean atomikosDataSource = new AtomikosDataSourceBean();
        atomikosDataSource.setUniqueResourceName("ccbDataSource");
        atomikosDataSource.setXaDataSource(druidXADataSource);
        atomikosDataSource.setTestQuery("SELECT 1");
        return atomikosDataSource;
    }

在这里我们返回的是AtomikosDataSourceBean ,是Druid实现的一个XA数据源也可以用注释中的MysqlXADataSource,配置了XAdatasource还需要将其转换为AtomikosDataSourceBean(Atomikos使用的是该数据源,用于包装不同的XA数据源实现,使得底层架构不变,对扩展开放),springboot默认配置的时候会使用AtomikosXADataSourceWrapper来包裹XAdatasource:

因为我们是手动注入DataSource,所以需要自己重新包装一次。

到此XA数据源和JTA事务都配置完毕,这时使用@Transactional注解将使用atomikos实现的事务管理器。

2.测试

还是沿用上节的测试代码,当我们执行testTransferAccountCcbToBocOnException()测试方法,会发现ccb库的数据成功回滚。而且根据console日志能查看事务提交和回滚的完整过程:

2018-04-02 23:15:49.536  INFO 14076 --- [           main] c.a.icatch.imp.BaseTransactionManager    : createCompositeTransaction ( 10000 ): created new ROOT transaction with id 10.100.144.36.tm0000100001
2018-04-02 23:15:49.574  INFO 14076 --- [           main] c.atomikos.jdbc.AbstractDataSourceBean   : AtomikosDataSoureBean 'ccbDataSource': getConnection ( null )...
2018-04-02 23:15:49.574  INFO 14076 --- [           main] c.atomikos.jdbc.AbstractDataSourceBean   : AtomikosDataSoureBean 'ccbDataSource': init...
2018-04-02 23:15:49.628  INFO 14076 --- [           main] c.a.icatch.imp.CompositeTransactionImp   : addParticipant ( XAResourceTransaction: 31302E3130302E3134342E33362E746D30303030313030303031:31302E3130302E3134342E33362E746D31 ) for transaction 10.100.144.36.tm0000100001
2018-04-02 23:15:49.628  INFO 14076 --- [           main] c.a.datasource.xa.XAResourceTransaction  : XAResource.start ( 31302E3130302E3134342E33362E746D30303030313030303031:31302E3130302E3134342E33362E746D31 , XAResource.TMNOFLAGS ) on resource ccbDataSource represented by XAResource instance com.mysql.jdbc.jdbc2.optional.MysqlXAConnection@3bc18fec
2018-04-02 23:15:49.689  INFO 14076 --- [           main] c.a.icatch.imp.CompositeTransactionImp   : registerSynchronization ( com.atomikos.jdbc.AtomikosConnectionProxy$JdbcRequeueSynchronization@a9775fbb ) for transaction 10.100.144.36.tm0000100001
2018-04-02 23:15:49.689  INFO 14076 --- [           main] c.atomikos.jdbc.AtomikosConnectionProxy  : atomikos connection proxy for com.alibaba.druid.proxy.jdbc.ConnectionProxyImpl@6c8d8b60: calling prepareStatement(UPDATE account_ccb SET balance = balance+? WHERE customer = ?;)...
2018-04-02 23:15:50.358  INFO 14076 --- [           main] c.f.service.impl.AccountCcbServiceImpl   : update balance ,[customer:10002,amount:-100]
2018-04-02 23:15:50.364  INFO 14076 --- [           main] c.atomikos.jdbc.AbstractDataSourceBean   : AtomikosDataSoureBean 'bocDataSource': getConnection ( null )...
2018-04-02 23:15:50.364  INFO 14076 --- [           main] c.atomikos.jdbc.AbstractDataSourceBean   : AtomikosDataSoureBean 'bocDataSource': init...
2018-04-02 23:15:50.367  INFO 14076 --- [           main] c.a.icatch.imp.CompositeTransactionImp   : addParticipant ( XAResourceTransaction: 31302E3130302E3134342E33362E746D30303030313030303031:31302E3130302E3134342E33362E746D32 ) for transaction 10.100.144.36.tm0000100001
2018-04-02 23:15:50.374  INFO 14076 --- [           main] c.a.datasource.xa.XAResourceTransaction  : XAResource.start ( 31302E3130302E3134342E33362E746D30303030313030303031:31302E3130302E3134342E33362E746D32 , XAResource.TMNOFLAGS ) on resource bocDataSource represented by XAResource instance com.mysql.jdbc.jdbc2.optional.MysqlXAConnection@33a8f553
2018-04-02 23:15:50.379  INFO 14076 --- [           main] c.a.icatch.imp.CompositeTransactionImp   : registerSynchronization ( com.atomikos.jdbc.AtomikosConnectionProxy$JdbcRequeueSynchronization@a9775fbb ) for transaction 10.100.144.36.tm0000100001
2018-04-02 23:15:50.379  INFO 14076 --- [           main] c.atomikos.jdbc.AtomikosConnectionProxy  : atomikos connection proxy for com.alibaba.druid.proxy.jdbc.ConnectionProxyImpl@5fe46d52: calling prepareStatement(UPDATE account_boc SET balance = balance+? WHERE customer = ?;)...
2018-04-02 23:15:50.451  INFO 14076 --- [           main] c.a.icatch.imp.CompositeTransactionImp   : setRollbackOnly() called for transaction 10.100.144.36.tm0000100001
2018-04-02 23:15:50.452  INFO 14076 --- [           main] c.atomikos.jdbc.AtomikosConnectionProxy  : atomikos connection proxy for com.alibaba.druid.proxy.jdbc.ConnectionProxyImpl@6c8d8b60: close()...
2018-04-02 23:15:50.452  INFO 14076 --- [           main] c.a.datasource.xa.XAResourceTransaction  : XAResource.end ( 31302E3130302E3134342E33362E746D30303030313030303031:31302E3130302E3134342E33362E746D31 , XAResource.TMSUCCESS ) on resource ccbDataSource represented by XAResource instance com.mysql.jdbc.jdbc2.optional.MysqlXAConnection@3bc18fec
2018-04-02 23:15:50.453  INFO 14076 --- [           main] c.atomikos.jdbc.AtomikosConnectionProxy  : atomikos connection proxy for com.alibaba.druid.proxy.jdbc.ConnectionProxyImpl@5fe46d52: close()...
2018-04-02 23:15:50.453  INFO 14076 --- [           main] c.a.datasource.xa.XAResourceTransaction  : XAResource.end ( 31302E3130302E3134342E33362E746D30303030313030303031:31302E3130302E3134342E33362E746D32 , XAResource.TMSUCCESS ) on resource bocDataSource represented by XAResource instance com.mysql.jdbc.jdbc2.optional.MysqlXAConnection@33a8f553
2018-04-02 23:15:50.456  INFO 14076 --- [           main] c.a.datasource.xa.XAResourceTransaction  : XAResource.rollback ( 31302E3130302E3134342E33362E746D30303030313030303031:31302E3130302E3134342E33362E746D31 ) on resource ccbDataSource represented by XAResource instance com.mysql.jdbc.jdbc2.optional.MysqlXAConnection@3bc18fec
2018-04-02 23:15:50.583  INFO 14076 --- [           main] c.a.datasource.xa.XAResourceTransaction  : XAResource.rollback ( 31302E3130302E3134342E33362E746D30303030313030303031:31302E3130302E3134342E33362E746D32 ) on resource bocDataSource represented by XAResource instance com.mysql.jdbc.jdbc2.optional.MysqlXAConnection@33a8f553
2018-04-02 23:15:50.587  INFO 14076 --- [           main] c.a.icatch.imp.CompositeTransactionImp   : rollback() done of transaction 10.100.144.36.tm0000100001

在上面的日志中我们可以看到,当其中一个事务失败,会JTA调用setRollbackOnly(),然后XAResource连接调用各自的rollback()方法进行回滚。
到本章为止,使用spring boot访问数据库,及多数据源和多数据源下的分布式事务都已经介绍完了,之后的章节可能会介绍如何使用拦截器和过滤器及其它的一些web应用中的常见技术在spring boot中的应用。

本章完整代码在:https://github.com/Json-Lin/spring-boot-practice/tree/master/spring-boot-practice-atomikos

END

你可能感兴趣的:(spring-boot)