当前位置: 首页 > news >正文

支持多数据源的 MyBatis-Plus 实现

1. 多数据源配置原理

在 Spring Boot 项目中使用 MyBatis-Plus 支持多数据源,通常需要基于 AbstractRoutingDataSource 实现动态数据源切换。其核心原理包括:

  1. 定义多个数据源:在 application.ymlapplication.properties 配置不同的数据源信息。
  2. 创建数据源 Bean:基于 DataSourceBuilder 初始化不同的数据源实例。
  3. 使用 AbstractRoutingDataSource:继承 AbstractRoutingDataSource,实现 determineCurrentLookupKey 方法,根据上下文切换数据源。
  4. 配置 MyBatis-Plus 关联多数据源:设置 SqlSessionFactoryDataSourceTransactionManager 关联不同的数据源。

示例配置:

spring:
  datasource:
    primary:
      url: jdbc:mysql://localhost:3306/db1
      username: root
      password: root
    secondary:
      url: jdbc:mysql://localhost:3306/db2
      username: root
      password: root

2. 动态切换数据源的实现

动态切换数据源的关键在于 AbstractRoutingDataSource 的使用和 AOP 方式实现方法级别的切换。

2.1 自定义数据源上下文管理

public class DataSourceContextHolder {
    private static final ThreadLocal<String> CONTEXT_HOLDER = new ThreadLocal<>();

    public static void setDataSource(String dataSourceKey) {
        CONTEXT_HOLDER.set(dataSourceKey);
    }

    public static String getDataSource() {
        return CONTEXT_HOLDER.get();
    }

    public static void clear() {
        CONTEXT_HOLDER.remove();
    }
}

2.2 继承 AbstractRoutingDataSource 实现动态路由

public class DynamicDataSource extends AbstractRoutingDataSource {
    @Override
    protected Object determineCurrentLookupKey() {
        return DataSourceContextHolder.getDataSource();
    }
}

2.3 AOP 方式切换数据源

@Aspect
@Component
public class DataSourceAspect {
    @Around("@annotation(targetDataSource)")
    public Object around(ProceedingJoinPoint point, TargetDataSource targetDataSource) throws Throwable {
        try {
            DataSourceContextHolder.setDataSource(targetDataSource.value());
            return point.proceed();
        } finally {
            DataSourceContextHolder.clear();
        }
    }
}

3. 数据源的管理与事务问题

多数据源事务管理主要涉及 同一数据源内事务保证跨数据源事务处理

3.1 单数据源事务管理

对于单个数据源,使用 @Transactional 即可正常管理事务。

@Transactional
public void updateUser(User user) {
    userMapper.updateById(user);
}

3.2 跨数据源事务处理(分布式事务)

由于 @Transactional 只能保证单数据源事务,需要使用 XA 事务TCC 分布式事务方案

  1. XA 事务:使用 Atomikos、Seata 进行全局事务管理。
  2. TCC 事务:利用 Try-Confirm-Cancel 模型管理跨数据源事务。

示例:基于 Seata 进行分布式事务管理

@GlobalTransactional
public void transferMoney(Long fromUserId, Long toUserId, BigDecimal amount) {
    accountService.decreaseBalance(fromUserId, amount);
    accountService.increaseBalance(toUserId, amount);
}

4. 多数据源使用中的性能优化

在多数据源场景下,合理优化性能可以减少数据库开销,提高系统吞吐量。

4.1 连接池优化

使用 HikariCP 作为连接池,并合理调整参数,如 maximumPoolSizeidleTimeoutconnectionTimeout 以减少连接创建开销。

示例配置:

spring:
  datasource:
    hikari:
      maximumPoolSize: 20
      idleTimeout: 30000
      connectionTimeout: 3000

4.2 减少数据源切换

避免在单个事务中频繁切换数据源,可通过业务拆分减少跨库操作。

4.3 读写分离

采用 主从数据库架构,结合 MyBatis-Plus 的多数据源策略,将 写操作 路由到主库,读操作 路由到从库,提升查询性能。

示例:

@TargetDataSource("slave")
public List<User> getUsers() {
    return userMapper.selectList(null);
}

5. @DS 注解与 AbstractRoutingDataSource 方式的对比

在 MyBatis-Plus 中,除了 AbstractRoutingDataSource 方式,还可以使用 @DS 注解指定数据源。

5.1 配置

如果使用 @DS 注解(Mybatis-Plus 自带的动态数据源切换),通常需要在 application.yml配置 dynamic,示例如下:

spring:
	datasource:
		dynamic:
			primary: master
			datasource:
				master:
					url: jdbc:mysql://localhost:3306/db1
					username: root
					password: root
				slave:
					url: jdbc:mysql://localhost:3306/db2
					username: root
					password: root

dynamic关键字在这里的作用是 让Mybatis-Plus知道这是一个动态数据源配置,否则@DS 注解无法生效。
如果使用 AbstractRoutingDataSource方式,dynamic 并不是必须的,因为动态数据源的管理是由 AbstractRoutingDataSource及其 determineCurrentLookupKey()方法控制的,数据源的配置可以直接放在 spring.datasource下

5.2 @DS 注解应用

MyBatis-Plus 提供 @DS 注解,可以直接在方法或类级别指定数据源。

@DS("secondary")
@Service
public class OrderService {
    public List<Order> getOrders() {
        return orderMapper.selectList(null);
    }
}

当 @DS 注解作用于类时,类中的所有方法都将默认使用该数据源,除非方法上另有 @DS 注解指定不同的数据源。

方式|适用场景|事务管理|代码侵入性

@DS 注解|方法或类级别的数据源切换|适用于单一方法调用,事务受限|低

AbstractRoutingDataSource|复杂的动态数据源路由|支持自定义事务策略|高

总结

  • @DS 适用于简单的场景,方便快捷。

  • AbstractRoutingDataSource 适用于需要更灵活的数据源控制,如基于用户、请求等动态切换数据源。

通过上述配置和优化,我们可以在 MyBatis-Plus 中实现灵活的多数据源支持,同时保证系统的稳定性和高效性。

相关文章:

  • C语言基础之【指针】(下)
  • Python的那些事第四十二篇:Python的无人机监控环境监测系统研究
  • macos查询pip默认镜像地址
  • 基于Hadoop的热门旅游景点推荐数据分析与可视化系统(基于Django大数据技术的热门旅游景点数据分析与可视化)
  • 抽象类与普通类的核心区别
  • Leetcode 264-丑数/LCR 168/剑指 Offer 49
  • QT异步编程
  • 无显示器安装访问树莓派3B+
  • C语言基础系列【19】inline关键字
  • 鸿蒙开发:RelativeContainer 相对布局详解【全套华为认证学习资料分享(考试大纲、培训教材、实验手册等等)】
  • 能源行业标杆:信创系统在智能电网中的3个创新应用案例
  • com.android.tools.r8.CompilationFailedException: Compilation failed to complete
  • lamp平台的应用
  • Towards Precise and Explainable Hardware Trojan Localization at LUT Level
  • L33.【LeetCode笔记】循环队列(数组解法)
  • ASP.NET Core 6 MVC 文件上传
  • 蓝桥杯P1259-奇怪的馈赠 (贪心题解)
  • File文件和目录
  • Milvus JSON数据存储优化方案
  • 宝塔 Linux 计划任务中添加运行项目网站PHP任务-定时任务
  • 持续推动深入贯彻中央八项规定精神学习教育走深走实!上海市委党建工作领导小组会议举行
  • 王楚钦球拍受损,乒乓球裁判揭秘大赛球拍检测
  • 上影节官方海报公布:电影之城,每一帧都是生活
  • “集团结婚”:近百年前革新婚俗的尝试
  • 英伟达推出新技术加速AI芯片连接,期望构建互联互通生态
  • 文化破冰,土耳其亚美尼亚合拍摄影大师阿拉·古勒传记片