Java多数据库访问与事务管理!

举报
喵手 发表于 2025/07/18 21:36:27 2025/07/18
【摘要】 开篇语哈喽,各位小伙伴们,你们好呀,我是喵手。运营社区:C站/掘金/腾讯云/阿里云/华为云/51CTO;欢迎大家常来逛逛  今天我要给大家分享一些自己日常学习到的一些知识点,并以文字的形式跟大家一起交流,互相学习,一个人虽可以走的更快,但一群人可以走的更远。  我是一名后端开发爱好者,工作日常接触到最多的就是Java语言啦,所以我都尽量抽业余时间把自己所学到所会的,通过文章的形式进行输出,...

开篇语

哈喽,各位小伙伴们,你们好呀,我是喵手。运营社区:C站/掘金/腾讯云/阿里云/华为云/51CTO;欢迎大家常来逛逛

  今天我要给大家分享一些自己日常学习到的一些知识点,并以文字的形式跟大家一起交流,互相学习,一个人虽可以走的更快,但一群人可以走的更远。

  我是一名后端开发爱好者,工作日常接触到最多的就是Java语言啦,所以我都尽量抽业余时间把自己所学到所会的,通过文章的形式进行输出,希望以这种方式帮助到更多的初学者或者想入门的小伙伴们,同时也能对自己的技术进行沉淀,加以复盘,查缺补漏。

小伙伴们在批阅的过程中,如果觉得文章不错,欢迎点赞、收藏、关注哦。三连即是对作者我写作道路上最好的鼓励与支持!

前言

在现代企业级应用中,系统的复杂度不断增加,数据源的多样性和分布式架构的需求也变得愈发重要。Java作为一种广泛应用于后端开发的编程语言,提供了多种方式来处理多数据源访问与事务管理。尤其是在企业级应用中,多个数据库和分布式事务的管理变得至关重要。如何高效地配置多个数据源,如何管理数据库事务,尤其是分布式事务,是每个开发者在构建高可用和高并发系统时必须掌握的技术。

本文将介绍如何在Java应用中实现多数据库访问,讲解Spring Data JPA和MyBatis的多数据源配置方法,并深入探讨事务管理的两种模式:声明式事务和编程式事务,最后将重点介绍分布式事务的管理,涵盖XA协议和TCC(Try-Confirm-Cancel)模式。

一、多数据源配置:Spring Data JPA与MyBatis

1.1 多数据源配置的背景

在一个企业级应用中,可能需要访问多个数据库,比如主数据库和多个子数据库(例如不同地区或部门的数据库),或同一数据的不同存储方式(例如关系型数据库与NoSQL数据库)。为了能够灵活处理多数据源访问,Java提供了不同的框架和工具来配置和管理多个数据源。

1.2 Spring Data JPA多数据源配置

Spring Data JPA是一个方便的框架,用于与关系型数据库进行交互,特别是在基于JPA(Java Persistence API)规范的数据库操作中。Spring Data JPA通过简化JPA实现(如Hibernate)来使得数据访问更容易。为了解决多数据源访问的问题,Spring提供了配置多个DataSource并通过@Primary注解选择主数据源的方法。

配置多个数据源

  1. 配置DataSource:在Spring配置中为每个数据源创建DataSource,分别指定数据库连接参数。
  2. 配置EntityManagerFactory:每个数据源都需要一个EntityManagerFactory来创建EntityManager,以便与JPA进行交互。
  3. 配置TransactionManager:每个数据源需要一个PlatformTransactionManager来管理事务。
@Configuration
@EnableTransactionManagement
public class DataSourceConfig {

    @Bean
    @Primary
    @ConfigurationProperties(prefix = "spring.datasource.primary")
    public DataSource primaryDataSource() {
        return DataSourceBuilder.create().build();
    }

    @Bean
    @ConfigurationProperties(prefix = "spring.datasource.secondary")
    public DataSource secondaryDataSource() {
        return DataSourceBuilder.create().build();
    }

    @Bean
    public LocalContainerEntityManagerFactoryBean entityManagerFactory(EntityManagerFactoryBuilder builder) {
        return builder
                .dataSource(primaryDataSource())  // 使用主数据源
                .packages("com.example.model")
                .persistenceUnit("primary")
                .build();
    }

    @Bean
    public PlatformTransactionManager transactionManager(EntityManagerFactory entityManagerFactory) {
        return new JpaTransactionManager(entityManagerFactory);
    }
}

在这个例子中,我们配置了两个数据源:primaryDataSourcesecondaryDataSource,并通过@Primary标注primaryDataSource为默认数据源。然后为每个数据源配置了EntityManagerFactoryTransactionManager,以便分别处理不同数据源的事务。

1.3 MyBatis多数据源配置

MyBatis是另一个常用的数据库访问框架,它为SQL语句提供了灵活的映射,允许开发者直接书写SQL语句进行数据操作。与Spring Data JPA类似,MyBatis也支持多数据源的配置。

配置多个数据源

  1. 配置DataSource:与Spring Data JPA相似,首先为每个数据源配置DataSource
  2. 配置SqlSessionFactory:每个数据源需要独立的SqlSessionFactory,用于执行SQL查询和映射。
  3. 配置TransactionManager:与Spring一样,事务管理对于每个数据源来说都是独立的。
@Configuration
@MapperScan(basePackages = "com.example.mapper.primary", sqlSessionFactoryRef = "primarySqlSessionFactory")
public class MyBatisConfig {

    @Bean
    @Primary
    @ConfigurationProperties(prefix = "spring.datasource.primary")
    public DataSource primaryDataSource() {
        return DataSourceBuilder.create().build();
    }

    @Bean
    public SqlSessionFactory primarySqlSessionFactory(@Qualifier("primaryDataSource") DataSource dataSource) throws Exception {
        SqlSessionFactoryBean sessionFactoryBean = new SqlSessionFactoryBean();
        sessionFactoryBean.setDataSource(dataSource);
        return sessionFactoryBean.getObject();
    }

    @Bean
    public PlatformTransactionManager primaryTransactionManager(@Qualifier("primaryDataSource") DataSource dataSource) {
        return new DataSourceTransactionManager(dataSource);
    }

    // 配置第二个数据源
    @Bean
    @ConfigurationProperties(prefix = "spring.datasource.secondary")
    public DataSource secondaryDataSource() {
        return DataSourceBuilder.create().build();
    }

    @Bean
    public SqlSessionFactory secondarySqlSessionFactory(@Qualifier("secondaryDataSource") DataSource dataSource) throws Exception {
        SqlSessionFactoryBean sessionFactoryBean = new SqlSessionFactoryBean();
        sessionFactoryBean.setDataSource(dataSource);
        return sessionFactoryBean.getObject();
    }

    @Bean
    public PlatformTransactionManager secondaryTransactionManager(@Qualifier("secondaryDataSource") DataSource dataSource) {
        return new DataSourceTransactionManager(dataSource);
    }
}

在上述代码中,我们配置了两个数据源(primaryDataSourcesecondaryDataSource),为每个数据源创建了独立的SqlSessionFactoryTransactionManager@MapperScan注解用于扫描指定的MyBatis Mapper接口。

二、事务管理:声明式事务与编程式事务

在Java中,事务管理是非常关键的一部分。事务可以保证数据一致性,防止在并发环境中发生数据冲突或不一致的情况。Java通过Spring框架提供了两种常见的事务管理模式:声明式事务编程式事务

2.1 声明式事务

声明式事务是指通过配置和注解来声明事务管理,而无需显式地在代码中编写事务处理逻辑。Spring提供了非常方便的声明式事务支持,可以通过@Transactional注解来实现。

示例:声明式事务

@Service
public class UserService {

    @Transactional
    public void transferMoney(String fromAccount, String toAccount, double amount) {
        // 执行数据库操作,转账逻辑
        accountDao.debit(fromAccount, amount);
        accountDao.credit(toAccount, amount);
    }
}

在这个例子中,@Transactional注解表示transferMoney方法需要在事务环境中执行。如果方法执行过程中发生异常,Spring会自动回滚事务,确保数据库的一致性。声明式事务的优势是简洁,不需要在代码中显式编写事务处理逻辑。

事务传播行为

Spring提供了多种事务传播行为,例如:

  • REQUIRED:如果当前存在事务,则加入该事务;如果当前没有事务,则新建一个事务。
  • REQUIRES_NEW:每次方法调用时都会新建一个事务。
  • NESTED:如果当前有事务,则在当前事务中嵌套一个子事务。

2.2 编程式事务

编程式事务需要开发者在代码中显式地编写事务管理逻辑。在这种方式中,开发者通过PlatformTransactionManager来手动管理事务的开始、提交和回滚。

示例:编程式事务

@Service
public class UserService {

    @Autowired
    private PlatformTransactionManager transactionManager;

    public void transferMoney(String fromAccount, String toAccount, double amount) {
        DefaultTransactionDefinition def = new DefaultTransactionDefinition();
        def.setIsolationLevel(TransactionDefinition.ISOLATION_READ_COMMITTED);
        def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
        TransactionStatus status = transactionManager.getTransaction(def);

        try {
            // 执行数据库操作
            accountDao.debit(fromAccount, amount);
            accountDao.credit(toAccount, amount);
            transactionManager.commit(status);  // 提交事务
        } catch (Exception e) {
            transactionManager.rollback(status);  // 回滚事务
            throw new RuntimeException("Transaction failed", e);
        }
    }
}

在这个例子中,我们手动创建了一个事务定义(DefaultTransactionDefinition),设置了事务的隔离级别和传播行为。通过transactionManager.getTransaction(def)开启事务,通过transactionManager.commit(status)提交事务,发生异常时通过transactionManager.rollback(status)回滚事务。

三、分布式事务:XA协议与TCC

在现代分布式系统中,事务往往跨越多个数据库或微服务,因此如何保证跨系统的一致性成为一个关键问题。常见的分布式事务解决方案有XA协议TCC(Try-Confirm-Cancel)模式。

3.1 XA协议

XA协议是一种两阶段提交协议(2PC),广泛用于分布式事务处理中。XA协议要求每个参与者(数据库)在事务开始时准备提交,并在事务结束时根据协调者的命令执行提交或回滚。

XA协议的基本流程

  1. 准备阶段:协调者向参与者发出“准备提交”的请求,参与者执行事务操作并进行准备。
  2. 提交阶段:如果所有参与者都准备好,则协调者发出“提交”命令,所有参与者执行提交操作;如果任何一个参与者准备失败,则发出“回滚”命令,所有参与者回滚事务。

XA协议的优点是简单,易于实现,但它会影响系统的性能和可用性,因为所有参与者必须等待协调者的指令。

3.2 TCC(Try-Confirm-Cancel)

TCC是一种基于补偿机制的分布式事务模型,适用于高并发的场景。TCC将分布式事务分为三个阶段:Try(尝试阶段)、Confirm(确认阶段)和Cancel(取消阶段)。在TCC模式下,每个服务都提供三种操作:

  • Try:预留资源并进行必要的检查(类似于预备提交)。
  • Confirm:在所有参与者都成功完成Try阶段后,确认操作并提交事务。
  • Cancel:如果有任何服务失败,则回滚前面成功的操作。

TCC的优点是高性能和更灵活的补偿机制,但实现起来比XA协议更复杂。

3.3 分布式事务管理框架

  • Atomikos:一个支持XA事务的分布式事务管理框架,适用于传统的两阶段提交协议。
  • Seata:一个分布式事务框架,支持TCC、AT、Saga等模式,特别适用于微服务架构。
  • Narayana:Red Hat提供的一个分布式事务管理框架,支持XA和TCC等协议。

四、总结

在现代Java开发中,多数据源访问和事务管理是构建高性能、可扩展应用的重要技术。Java 通过Spring和MyBatis等框架提供了方便的多数据源配置和事务管理支持,使得开发者能够轻松管理复杂的数据库访问和事务。尤其在分布式系统中,正确选择和实现分布式事务协议(如XA协议或TCC)对于确保系统的一致性和稳定性至关重要。

通过掌握多数据源配置、声明式事务与编程式事务的实现,以及分布式事务的管理策略,开发者能够构建出更加健壮、灵活和高效的系统,为现代企业级应用打下坚实的基础。

… …

文末

好啦,以上就是我这期的全部内容,如果有任何疑问,欢迎下方留言哦,咱们下期见。

… …

学习不分先后,知识不分多少;事无巨细,当以虚心求教;三人行,必有我师焉!!!

wished for you successed !!!


⭐️若喜欢我,就请关注我叭。

⭐️若对您有用,就请点赞叭。
⭐️若有疑问,就请评论留言告诉我叭。


版权声明:本文由作者原创,转载请注明出处,谢谢支持!

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。