spring boot项目整合mybatis实现多数据源的配置

在我们日常的开发中,经常会用到一个项目中使用多个数据源的问题,本次就带你了解怎样在spring boot项目中使用mybatis整合多个数据源的示例。使用spring boot3.5版本

1、创建一个spring boot项目,并引入相应的maven依赖

java 复制代码
 <dependencies>

        <dependency>
            <groupId>com.github.xiaoymin</groupId>
            <artifactId>knife4j-openapi3-jakarta-spring-boot-starter</artifactId>
            <version>4.5.0</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>com.mysql</groupId>
            <artifactId>mysql-connector-j</artifactId>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>3.0.3</version>
        </dependency>

        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid-spring-boot-starter</artifactId>
            <version>1.2.20</version>
        </dependency>


        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

2、在配置文件中设置相应的连接信息

java 复制代码
spring:
  datasource:
    # 主数据源
    zh:
      jdbc-url: jdbc:mysql://localhost:3306/zh?useSSl=false&useUnicode=true&characterEncoding=utf-8&serverTimezone=UTC
      username: root
      password: 123456
      type: com.alibaba.druid.pool.DruidDataSource
      driver-class-name: com.mysql.cj.jdbc.Driver
      # 次数据源
    en:
      jdbc-url: jdbc:mysql://localhost:3306/en?useSSl=false&useUnicode=true&characterEncoding=utf-8&serverTimezone=UTC
      username: root
      password: 123456
      type: com.alibaba.druid.pool.DruidDataSource
      driver-class-name: com.mysql.cj.jdbc.Driver
mybatis:
  mapper-locations: classpath:/mapper/**/*.xml
  configuration:
    map-underscore-to-camel-case: true

这里需要注意的一点是,我们引入了mybatis-springboot的自动装配的依赖,那么,项目在启动的时候会检查我们有没有配置默认的数据源连接信息,如果没有配置会报错。这个时候我们有两种解决思路。一种是在配置文件中指定一下连接信息,但是这个数据连接信息我们不用,另一种是把数据源自动配置的bean给排除掉。需要在启动类上指定

java 复制代码
@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class})

3、手动指定多数据源的连接配置

我的项目中是指定了两套数据源,分别为zh、en。我只需要配置两套数据连接信息即可;

配置zh数据库的连接配置:

java 复制代码
@Configuration
@MapperScan(
    basePackages = "com.zq.testmybatis.mapper.zh",
    sqlSessionFactoryRef = "zhSqlSessionFactory"
)
public class ZhMyBatisConfig {




    /**
     * 创建并返回一个以 "spring.datasource.zh" 为前缀的配置属性绑定的数据源对象。
     *
     * @return DataSource 对象
     */
    @Primary
    @Bean
    @ConfigurationProperties(prefix = "spring.datasource.zh")
    public DataSource zhDataSource() {
        return DataSourceBuilder.create().build();
    }

    /**
     * 创建中文数据库SQL会话工厂。
     *
     * @param dataSource 数据源,必须被标注为@Qualifier("zhDataSource")
     * @return SqlSessionFactory 对象
     * @throws Exception 抛出异常
     */
    @Primary
    @Bean
    public SqlSessionFactory zhSqlSessionFactory(
            @Qualifier("zhDataSource") DataSource dataSource) throws Exception {
        SqlSessionFactoryBean sessionFactory = new SqlSessionFactoryBean();
        sessionFactory.setDataSource(dataSource);
        // 重点:手动启用驼峰映射
        org.apache.ibatis.session.Configuration configuration = new org.apache.ibatis.session.Configuration();
        configuration.setMapUnderscoreToCamelCase(true); // 启用驼峰映射
        sessionFactory.setConfiguration(configuration);
        sessionFactory.setMapperLocations(
            new PathMatchingResourcePatternResolver()
                .getResources("classpath:mapper/zh/**/*.xml"));
        return sessionFactory.getObject();
    }

    /**
     * 创建一个名为zhSqlSessionTemplate的SqlSessionTemplate对象,该对象使用名为zhSqlSessionFactory的SqlSessionFactory。
     *
     * @param sqlSessionFactory 类型为SqlSessionFactory,用于创建SqlSessionTemplate对象的SqlSessionFactory。
     * @return 返回类型为SqlSessionTemplate的zhSqlSessionTemplate对象。
     */
    @Primary
    @Bean
    public SqlSessionTemplate zhSqlSessionTemplate(
            @Qualifier("zhSqlSessionFactory") SqlSessionFactory sqlSessionFactory) {
        return new SqlSessionTemplate(sqlSessionFactory);
    }
}

配置en数据库的连接信息:

java 复制代码
@Configuration
@MapperScan(
    basePackages = "com.zq.testmybatis.mapper.en",
    sqlSessionFactoryRef = "enSqlSessionFactory"
)
public class EnMyBatisConfig {

    /**
     * 创建并返回一个名为 "enDataSource" 的数据源。
     *
     * @return 返回一个配置为 "spring.datasource.en" 前缀的配置属性的数据源
     */
    @Bean
    @ConfigurationProperties(prefix = "spring.datasource.en")
    public DataSource enDataSource() {
        return DataSourceBuilder.create().build();
    }

    /**
     * 创建一个 SqlSessionFactory Bean,使用指定的数据源。
     *
     * @param dataSource 数据源,通过 @Qualifier 注解指定
     * @return SqlSessionFactory 对象
     * @throws Exception 如果在创建 SqlSessionFactory 过程中发生异常
     */
    @Bean
    public SqlSessionFactory enSqlSessionFactory(
            @Qualifier("enDataSource") DataSource dataSource) throws Exception {
        SqlSessionFactoryBean sessionFactory = new SqlSessionFactoryBean();
        sessionFactory.setDataSource(dataSource);
        // 重点:手动启用驼峰映射
        org.apache.ibatis.session.Configuration configuration = new org.apache.ibatis.session.Configuration();
        configuration.setMapUnderscoreToCamelCase(true); // 启用驼峰映射
        sessionFactory.setConfiguration(configuration);
        sessionFactory.setMapperLocations(
            new PathMatchingResourcePatternResolver()
                .getResources("classpath:mapper/en/**/*.xml"));
        return sessionFactory.getObject();
    }

    /**
     * 创建一个SqlSessionTemplate对象
     *
     * @param sqlSessionFactory 数据库会话工厂,通过@Qualifier注解指定使用"enSqlSessionFactory"
     * @return 返回创建的SqlSessionTemplate对象
     */
    @Bean
    public SqlSessionTemplate enSqlSessionTemplate(
            @Qualifier("enSqlSessionFactory") SqlSessionFactory sqlSessionFactory) {
        return new SqlSessionTemplate(sqlSessionFactory);
    }
}

这里需要我们注意的主要有两点:mapper接口的扫射路径、XML文件的扫射路径;

还有一点要注意的是,由于我们是手动指定了XML路径的连接信息,所有如果spring项目在启动时扫描到你指定的XML地址下没有相应的XML文件时,项目会报错。

4、使用多数据源

配置好了以上的所有信息之后,我们就可以正常的使用mapper接口来进行数据操作了。这里要提醒的一点是,两个数据源的mapper接口尽量不要相同,因为我们是在同一个spring boot中,也就是这两个mapper接口都会被扫描到IOC容器中。

java 复制代码
@RestController
public class TestController {
@Resource
    private EnUserMapper enUserMapper;
@Resource
    private ZhUserMapper zhUserMapper;
@PostMapping("/addEnUser")
public String addEnUser(@RequestBody EnUser enUser) {
    enUserMapper.insert(enUser);
    return "success";
}
@GetMapping("/getEnUser")
public List<EnUser> getEnUser() {
    return enUserMapper.listAll();
}
    @PostMapping("/addZHUser")
    public String addZhUser(@RequestBody ZhUser zhUser) {
        zhUserMapper.insert(zhUser);
        return "success";
    }
@GetMapping("/getZhUser")
    public List<ZhUser> getZhUser() {
        return zhUserMapper.listAll();
    }
    
}

就和我们正常使用一样就可以了;

5、多数据源的事务一致性

在单个数据源中,我们只需要使用@Transactional注解就能保证事务的一致性,但是在多数据源中不行,但是同样有解决的办法,我们可以使用JTA分布式事务(Atomikos)或者分布式事务seata

首先介绍一下JTA是基于XA协议的两阶段提交(2PC),属于Java EE规范的一部分。事务由应用服务器(如WebLogic、JBoss)的事务管理器(TM)协调,数据库作为资源管理器(RM)实现XA接口它的工作流程为:

  • 阶段一:TM询问所有RM是否可提交,RM锁定资源并返回准备状态。

  • 阶段二:TM根据RM反馈决定全局提交或回滚。

  • 特点:强一致性,但存在同步阻塞(阶段一锁定资源)和单点故障风险。

seata是阿里巴巴开源分布式事务框架,相应的特性可以看我之前写的这篇文章:

seata的快速入门和实战_seata快速入门-CSDN博客

维度 JTA/XA Seata
事务模型 基于XA协议的2PC 支持AT、TCC、Saga、XA多种模式
一致性 强一致性(实时生效) AT模式为最终一致性,TCC/XA为强一致性
性能 低(阶段一长期锁资源) 高(AT模式一阶段提交释放锁)14
侵入性 无代码侵入,依赖数据库XA驱动 AT模式无侵入,TCC需业务编码补偿逻辑57
架构依赖 强依赖应用服务器(如WebLogic) 独立中间件,与Spring Cloud等微服务框架集成26
资源要求 数据库需支持XA协议 AT模式无需XA驱动,仅需本地事务支持13
锁机制 数据库行锁 AT模式通过全局锁(lock_table)避免脏写

这两种方法都能解决多数据源的数据不一致问题,具体使用哪一种就看你自己的业务场景了。

相关推荐
码不停蹄的玄黓4 分钟前
通关JUC:Java并发工具包从入门到精通 | 深度源码解析
java·jvm·spring boot·spring·spring cloud
一只编程菜鸟5 分钟前
Java + easyexcel 新旧数据对比,单元格值标红
java·开发语言
年老体衰按不动键盘24 分钟前
idea中导入maven项目的方法
java·maven·intellij-idea
jdyzzy34 分钟前
从0到1做一个“任务管理系统”:Spring Boot + Vue 实战教程(含源码)
vue.js·spring boot·后端
步、步、为营35 分钟前
.NET10:asp.net core mini api中的验证
java·asp.net·.net
麦兜*1 小时前
【为什么RabbitMQ能够控制事务?控制事务的原理】
java·rabbitmq·java-rabbitmq
温温top1 小时前
java中合并音频
java·音视频
九转苍翎1 小时前
Java SE(13)——工具类
java·工具类
小马爱打代码1 小时前
数据结构 - Java 队列
java·数据结构
盖世英雄酱581362 小时前
🚀不改SQL,也能让SQL的执行效率提升100倍
java·数据库·后端