ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

MyBatis-Plus多数据源配置与动态路由实战

MyBatis-Plus多数据源配置与动态路由实战 1. 多数据源配置的核心价值与场景解析在真实的企业级应用开发中单数据源往往难以满足复杂的业务需求。我经历过一个电商项目需要同时对接主业务库、财务库和物流库传统的单数据源模式会导致代码中充斥大量硬编码的JDBC连接切换逻辑。MyBatis-Plus结合dynamic-datasource的多数据源方案正是解决这类痛点的利器。这种方案的核心优势在于业务透明性开发人员无需关心具体操作哪个数据库通过注解即可切换动态路由能力可根据业务参数在运行时动态选择数据源事务管理支持跨数据源的分布式事务需结合Seata等框架性能优化内置连接池管理避免频繁创建销毁连接典型应用场景包括多租户SaaS系统每个租户独立数据库读写分离架构主库写从库读分库分表前的过渡方案异构数据库整合如MySQLOracle混合使用重要提示多数据源配置会增加系统复杂度在单库能满足需求时不要过度设计。我曾见过团队为了技术先进性强行上多数据源反而导致维护成本飙升的案例。2. 环境准备与依赖配置2.1 版本匹配要点当前主流组合方案Spring Boot 2.7.x MyBatis-Plus 3.5.3.xSpring Boot 3.x MyBatis-Plus 3.5.4我推荐使用经过验证的稳定组合dependency groupIdcom.baomidou/groupId artifactIdmybatis-plus-boot-starter/artifactId version3.5.3.1/version /dependency dependency groupIdcom.baomidou/groupId artifactIddynamic-datasource-spring-boot-starter/artifactId version3.6.1/version /dependency2.2 Druid连接池集成虽然dynamic-datasource自带HikariCP但国内项目更常用Druid。配置示例spring: datasource: druid: stat-view-servlet: enabled: true login-username: admin login-password: admin filters: stat,wall filter: stat: slow-sql-millis: 1000 log-slow-sql: true2.3 多数据源基础配置spring: datasource: dynamic: primary: master # 默认数据源 strict: false # 是否严格匹配数据源 datasource: master: url: jdbc:mysql://localhost:3306/master_db username: root password: 123456 driver-class-name: com.mysql.cj.jdbc.Driver type: com.alibaba.druid.pool.DruidDataSource slave1: url: jdbc:mysql://localhost:3306/slave_db1 username: root password: 123456 driver-class-name: com.mysql.cj.jdbc.Driver type: com.alibaba.druid.pool.DruidDataSource3. 核心实现与注解使用3.1 DS注解深度解析DS是动态数据源的核心注解支持以下使用场景方法级注解最常用DS(slave1) public ListUser getUsers() { return userMapper.selectList(null); }类级注解该类所有方法默认使用该数据源DS(master) Repository public class UserDaoImpl implements UserDao { // 所有方法默认使用master数据源 }注解继承规则方法注解优先于类注解接口上的注解不生效因为Spring AOP基于实现类3.2 动态数据源切换原理核心流程通过AOP拦截被DS注解的方法从注解值或SpEL表达式中解析目标数据源名称将数据源key设置到DynamicDataSourceContextHolder执行SQL前通过AbstractRoutingDataSource确定实际数据源执行完成后清理线程上下文踩坑记录我曾遇到DS注解在同类方法调用时不生效的问题这是因为Spring AOP的代理机制导致的。解决方案是注入自身代理或通过ApplicationContext获取bean。4. 高级特性与实战技巧4.1 分页插件集成MyBatis-Plus的分页在多数据源环境下需要特殊处理Configuration public class MybatisPlusConfig { Bean public MybatisPlusInterceptor mybatisPlusInterceptor() { MybatisPlusInterceptor interceptor new MybatisPlusInterceptor(); // 分页插件 interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL)); return interceptor; } }使用示例DS(slave1) public PageUser getUsersByPage(int pageNum, int pageSize) { PageUser page new Page(pageNum, pageSize); return userMapper.selectPage(page, null); }4.2 多数据源事务管理默认情况下Transactional和DS注解组合使用时会有问题。解决方案方案一使用分布式事务框架如Seata方案二避免跨数据源事务方案三自定义事务管理器DS(master) Transactional(rollbackFor Exception.class) public void updateMaster(User user) { userMapper.updateById(user); // 调用其他数据源方法需要特殊处理 ((UserService)AopContext.currentProxy()).updateSlave(user); } DS(slave1) public void updateSlave(User user) { userMapper.updateById(user); }4.3 动态数据源扩展实现动态数据源路由public class DynamicDataSourceStrategy implements DynamicDataSourceStrategy { Override public String determineDataSourceKey( DynamicDataSourceContextHolder contextHolder) { // 从请求参数或线程上下文获取路由key String tenantId TenantContext.getCurrentTenant(); return ds_ tenantId; } }配置spring: datasource: dynamic: strategy: com.example.config.DynamicDataSourceStrategy5. 性能优化与问题排查5.1 连接池配置建议spring: datasource: druid: # 初始连接数 initial-size: 5 # 最小空闲连接数 min-idle: 5 # 最大活跃连接数 max-active: 20 # 获取连接等待超时时间 max-wait: 60000 # 配置间隔多久检测需要关闭的空闲连接 time-between-eviction-runs-millis: 60000 # 连接最小生存时间 min-evictable-idle-time-millis: 3000005.2 常见问题排查指南问题现象可能原因解决方案数据源切换不生效1. 注解位置错误2. 同类方法调用1. 检查注解位置2. 使用AopContext事务回滚失效跨数据源事务使用分布式事务或重构代码连接泄漏连接未正确关闭检查事务边界配置Druid监控性能下降连接池配置不当调整连接池参数监控使用情况5.3 监控与调优启用Druid监控Bean public ServletRegistrationBeanStatViewServlet druidStatViewServlet() { ServletRegistrationBeanStatViewServlet reg new ServletRegistrationBean(); reg.setServlet(new StatViewServlet()); reg.addUrlMappings(/druid/*); return reg; }关键监控指标活跃连接数等待线程数SQL执行时间慢SQL记录6. 项目实战若依框架改造案例以若依4.8.3非分离版改造为例移除原有Mybatis依赖添加Mybatis-Plusdependency groupIdcom.baomidou/groupId artifactIdmybatis-plus-boot-starter/artifactId version3.5.3.1/version /dependency修改application.yml配置多数据源重构原有Mapper接口// 原接口 public interface UserMapper { Select(SELECT * FROM sys_user WHERE user_id #{userId}) SysUser selectUserById(Long userId); } // 改为 public interface UserMapper extends BaseMapperSysUser { DS(slave) // 添加数据源注解 Select(SELECT * FROM sys_user WHERE user_id #{userId}) SysUser selectUserById(Long userId); }分页改造// 原代码 PageHelper.startPage(pageNum, pageSize); ListSysUser list userMapper.selectUserList(user); PageInfoSysUser pageInfo new PageInfo(list); // 改为 PageSysUser page new Page(pageNum, pageSize); userMapper.selectPage(page, Wrappers.SysUserlambdaQuery() .eq(SysUser::getStatus, 0));改造过程中的经验先从小模块开始试点注意原有XML中特殊SQL的兼容处理分页参数传递方式的变化需要统一调整
返回列表