专业编程教程与实战项目分享平台

网站首页 > 技术文章 正文

Spring Boot JDBC JTA分布式事务(springboot+jdbc)

ins518 2025-07-28 16:59:45 技术文章 38 ℃ 0 评论

在《Spring Boot JDBC多数据源》中,我们已经可以使用多个数据源为服务提供持久化能力。在单个数据源的时候,我们可以借助数据库本身的事务机制,保持数据的一致性,那么,在多个数据源的情况下,我们如何保证数据的一致性呢?这一章节我们来了解一下。

什么是分布式事务

要了解多个数据源如何保持数据一致性时,我们先来看一个概念:分布式事务。究竟什么是分布式事务呢?

简单来说,一个事务包含多个操作,多个操作操作了多个数据源,这样的事务称为分布式事务。

什么是JTA

说起JTA,我们就需要说一下XA协议了。

  • XA协议:XA是X/Open DTP组织(X/Open DTP group)定义的包含:两阶段提交协议,三阶段提交协议,XA被许多数据库(如Oracle、DB2、SQL Server、MySQL)和中间件等工具(如CICS 和 Tuxedo)支持 。
  • JTA:JTA(Java Transaction API),是J2EE的编程接口规范,它是XA协议的JAVA实现。某种程度上,可以认为JTA规范是XA规范的Java版。
  • Atomikos:Atomikos是一个分布式事务管理器,是JTA / XA的具体实现,提供的功能比JTA / XA所要求的更多

JTA示意图:

Spring Boot JTA实例

引入pom依赖

<dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-jta-atomikos</artifactId>
</dependency>

配置文件

spring:
  datasource:
    primary:
      uniqueResourceName: primary
      xaDataSourceClassName: com.mysql.cj.jdbc.MysqlXADataSource
      xaProperties:
        url: jdbc:mysql://ip:port/springboot_demo?characterEncoding=utf-8&allowMultiQueries=true&autoReconnect=true
        user: root
        password: xxxxxxx
      exclusiveConnectionMode: true
      minPoolSize: 3
      maxPoolSize: 10
    second:
      uniqueResourceName: second
      xaDataSourceClassName: com.mysql.cj.jdbc.MysqlXADataSource
      xaProperties:
        url: jdbc:mysql://ip:port/springboot_demo_2?characterEncoding=utf-8&allowMultiQueries=true&autoReconnect=true
        user: root
        password: xxxxxxx
      exclusiveConnectionMode: true
      minPoolSize: 3
      maxPoolSize: 10

数据源配置

@Configuration
public class DataSourceConfig {

    @Bean(initMethod = "init", destroyMethod = "close", name = "primaryDataSource")
    @ConfigurationProperties(prefix = "spring.datasource.primary")
    @Primary
    public DataSource primaryDataSource() {
        return new AtomikosDataSourceBean();
    }

    @Bean(initMethod = "init", destroyMethod = "close", name = "secondDataSource")
    @Qualifier("secondDataSource")
    @ConfigurationProperties(prefix = "spring.datasource.second")
    public DataSource secondDataSource() {
        return new AtomikosDataSourceBean();
    }
}

JdbcTemplate配置

@Configuration
public class JdbcTemplateConfig {

    @Bean(name = "primaryJdbcTemplate")
    public JdbcTemplate primaryJdbcTemplate(
            @Qualifier("primaryDataSource") DataSource dataSource) {
        return new JdbcTemplate(dataSource);
    }

    @Bean(name = "secondJdbcTemplate")
    public JdbcTemplate secondaryJdbcTemplate(
            @Qualifier("secondDataSource") DataSource dataSource) {
        return new JdbcTemplate(dataSource);
    }
}

统一事务配置

@Configuration
public class TransacationManagerConfig {

    @Bean
    public UserTransaction userTransaction() throws SystemException {
        UserTransaction userTransaction = new UserTransactionImp();
        userTransaction.setTransactionTimeout(10000);
        return userTransaction;
    }

    @Bean(name = "atomikosTransactionManager", initMethod = "init", destroyMethod = "close")
    public TransactionManager atomikosTransacationManager() throws Throwable{
        UserTransactionManager userTransactionManager = new UserTransactionManager();
        userTransactionManager.setForceShutdown(false);
        return userTransactionManager;
    }

    @Bean(name = "transacationManager")
    public PlatformTransactionManager transactionManager() throws Throwable {
        UserTransaction userTransaction = new UserTransactionImp();
        JtaTransactionManager manager = new JtaTransactionManager(userTransaction, atomikosTransacationManager());
        return manager;
    }
}

测试

由于是在上个工程

《JDBC读数据源》

https://gitee.com/pftian/spring-boot-learning/tree/master/spring-boot-jdbc-multiple-datasource

的基础上做的改造,我们直接编写测试用例。

@SpringBootTest(classes = JDBCApplication.class)
public class JTATest {


    @Autowired
    UserService userService;
    @Autowired
    LogService logService;

    @Test
    @Transactional
    public void testJTATransaction() {
        User user = new User();
        Log log = new Log();

        user.setBorthday(new Date());
        user.setName("jta");
        log.setLogTime(new Date());
        log.setIp("22222");
        log.setMethod("xxxxx");
        userService.save(user);
        logService.save(log);
        // 手动制造异常
        int a = 100/0;
    }
}

伙伴们,行动起来,加油!!!

源码地址:Spring Boot Learning: 学习springboot中的各个组件,编写示例工程 运行spring-boot-jdbc-jta工程。

Tags:

本文暂时没有评论,来添加一个吧(●'◡'●)

欢迎 发表评论:

最近发表
标签列表