若依(RuoYi)整合异构数据库:基于MyBatis-Plus与Dynamic-Datasource的多源实战
1. 为什么需要多数据源整合?
在实际开发中,我们经常会遇到需要同时操作多个数据库的场景。比如你可能需要从MySQL中读取用户信息,同时又要从Oracle中获取订单数据,最后还要把统计结果写入SQLite本地缓存库。这种跨数据库操作的需求在数据中台、报表系统、数据迁移工具等场景中尤为常见。
若依(RuoYi)作为一款优秀的开源后台管理系统框架,本身已经集成了MyBatis-Plus这个强大的ORM工具。但原生的单数据源配置无法满足多数据库操作的需求。这时候就需要引入Dynamic-Datasource这个动态数据源组件,它能够让我们像操作单个数据库一样轻松管理多个数据源。
我最近在一个电商后台项目中就遇到了这样的需求:需要同时连接SQL Server的业务数据库和SQLite的本地配置库。通过MyBatis-Plus和Dynamic-Datasource的组合,最终实现了优雅的多数据源解决方案。下面我就把这个实战经验完整分享给大家。
2. 环境准备与依赖配置
2.1 必备依赖引入
首先需要在项目的pom.xml中添加必要的依赖。除了MyBatis-Plus的基础依赖外,最关键的是dynamic-datasource-spring-boot-starter和数据库驱动。
<!-- MyBatis-Plus核心依赖 --> <dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-boot-starter</artifactId> <version>3.5.1</version> </dependency> <!-- 动态数据源核心组件 --> <dependency> <groupId>com.baomidou</groupId> <artifactId>dynamic-datasource-spring-boot-starter</artifactId> <version>3.5.2</version> </dependency> <!-- 数据库驱动(按需添加) --> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>8.0.28</version> </dependency> <dependency> <groupId>com.oracle.database.jdbc</groupId> <artifactId>ojdbc8</artifactId> <version>21.5.0.0</version> </dependency> <dependency> <groupId>org.xerial</groupId> <artifactId>sqlite-jdbc</artifactId> <version>3.36.0.3</version> </dependency> <dependency> <groupId>com.microsoft.sqlserver</groupId> <artifactId>mssql-jdbc</artifactId> <version>10.2.3.jre8</version> </dependency> <!-- Druid连接池(推荐) --> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid-spring-boot-starter</artifactId> <version>1.2.16</version> </dependency>2.2 数据库驱动选择技巧
不同数据库的驱动版本选择有讲究:
- MySQL 8.x推荐使用8.0.x版本的驱动
- Oracle建议使用ojdbc8
- SQLite选择稳定版的sqlite-jdbc
- SQL Server注意jre8和jre11版本的区别
我曾经因为驱动版本不匹配导致连接失败,排查了半天才发现是SQL Server驱动版本问题。建议大家在引入依赖时仔细核对版本号。
3. 多数据源配置详解
3.1 YAML配置文件解析
在若依框架中,数据源配置通常在application-druid.yml中。我们需要修改这个文件来支持多数据源:
spring: autoconfigure: exclude: com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceAutoConfigure datasource: type: com.alibaba.druid.pool.DruidDataSource dynamic: primary: master # 设置默认数据源 strict: false # 是否严格匹配数据源,默认false datasource: master: # 主库 url: jdbc:mysql://localhost:3306/ruoyi?useUnicode=true&characterEncoding=utf8&serverTimezone=GMT%2B8 username: root password: 123456 driver-class-name: com.mysql.cj.jdbc.Driver druid: initial-size: 5 max-active: 20 oracle: # Oracle从库 url: jdbc:oracle:thin:@localhost:1521:ORCL username: system password: oracle123 driver-class-name: oracle.jdbc.OracleDriver sqlite: # SQLite本地库 url: jdbc:sqlite:sql/local.db driver-class-name: org.sqlite.JDBC sqlserver: # SQL Server业务库 url: jdbc:sqlserver://localhost:1433;databaseName=BusinessDB username: sa password: sqlserver123 driver-class-name: com.microsoft.sqlserver.jdbc.SQLServerDriver3.2 配置项关键点说明
- primary:指定默认数据源,当不指定数据源时会使用这个
- strict:设为true时,未匹配的数据源会抛出异常,false则自动使用默认数据源
- druid连接池配置:可以针对每个数据源单独配置,也可以全局配置
我在实际项目中发现,对于SQLite这种文件型数据库,连接池的max-active不宜设置过大,一般5-10就够了,否则可能会导致文件锁冲突。
4. 动态数据源实战应用
4.1 注解方式切换数据源
Dynamic-Datasource最方便的特性就是通过@DS注解来切换数据源:
@Service public class UserServiceImpl implements UserService { @Autowired private UserMapper userMapper; // 默认使用主数据源 public List<User> getMasterUsers() { return userMapper.selectList(null); } @DS("oracle") // 切换到Oracle数据源 public List<User> getOracleUsers() { return userMapper.selectList(null); } @DS("sqlserver") // 切换到SQL Server数据源 public List<User> getSqlServerUsers() { return userMapper.selectList(null); } }4.2 事务处理注意事项
在多数据源环境下,事务管理需要特别注意:
@DS("master") @Transactional // 这里的事务只对master数据源有效 public void crossDatabaseOperation() { // 操作master数据源 userMapper.updateById(...); // 切换到oracle数据源 oracleOperation(); } @DS("oracle") public void oracleOperation() { // 这里的事务与上层方法是独立的 orderMapper.updateById(...); }如果确实需要跨数据源事务,可以考虑使用JTA或Seata等分布式事务解决方案,但这会显著增加系统复杂度。在大多数场景下,通过业务逻辑保证最终一致性是更实用的选择。
5. Druid监控配置优化
5.1 监控页面配置
Druid提供了强大的监控功能,我们需要在DruidConfig类中配置:
@Configuration public class DruidConfig { @Bean public ServletRegistrationBean<StatViewServlet> druidServlet() { ServletRegistrationBean<StatViewServlet> servletRegistrationBean = new ServletRegistrationBean<>(); servletRegistrationBean.setServlet(new StatViewServlet()); servletRegistrationBean.addUrlMappings("/druid/*"); // 控制台管理用户名密码 servletRegistrationBean.addInitParameter("loginUsername", "admin"); servletRegistrationBean.addInitParameter("loginPassword", "admin123"); return servletRegistrationBean; } @Bean public FilterRegistrationBean<WebStatFilter> filterRegistrationBean() { FilterRegistrationBean<WebStatFilter> filterRegistrationBean = new FilterRegistrationBean<>(); filterRegistrationBean.setFilter(new WebStatFilter()); filterRegistrationBean.addUrlPatterns("/*"); filterRegistrationBean.addInitParameter("exclusions", "*.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid/*"); return filterRegistrationBean; } }5.2 多数据源监控技巧
在多数据源环境下,我们需要为每个数据源单独配置监控:
spring: datasource: dynamic: datasource: master: druid: stat-view-servlet: enabled: true login-username: admin login-password: admin123 allow: 127.0.0.1 oracle: druid: stat-view-servlet: enabled: true这样每个数据源都有独立的监控入口,可以分别查看SQL执行情况、连接池状态等信息。
6. 常见问题排查指南
6.1 连接失败问题排查
当遇到数据源连接失败时,可以按照以下步骤排查:
- 检查驱动类名是否正确
- 确认URL格式符合对应数据库的要求
- 验证用户名密码是否正确
- 检查网络连接是否通畅
- 查看数据库服务是否正常运行
特别是Oracle和SQL Server,它们的URL格式比较特殊,容易写错。SQLite则需要注意文件路径权限问题。
6.2 性能调优建议
多数据源环境下,连接池配置尤为关键:
- 根据业务压力调整max-active大小
- 设置合理的validationQuery
- 配置适当的超时时间
- 开启慢SQL监控
- 定期检查连接泄漏
我曾经遇到过一个线上问题,由于max-active设置过大导致数据库连接数爆满。后来通过Druid监控发现后,调整到合理值就解决了。
7. 高级应用场景
7.1 动态添加数据源
除了配置文件中的静态数据源,我们还可以在运行时动态添加:
@Autowired private DynamicRoutingDataSource dynamicRoutingDataSource; public void addDynamicDataSource(String poolName, DataSourceProperty property) { DruidDataSource dataSource = dynamicDataSourceCreator.createDataSource(property); dynamicRoutingDataSource.addDataSource(poolName, dataSource); }这个特性在SaaS多租户系统中特别有用,可以根据租户需求动态创建数据源。
7.2 读写分离实现
结合Dynamic-Datasource的负载均衡特性,可以轻松实现读写分离:
spring: datasource: dynamic: datasource: master: type: com.alibaba.druid.pool.DruidDataSource url: jdbc:mysql://master:3306/db username: root password: 123456 slave_1: url: jdbc:mysql://slave1:3306/db username: root password: 123456 slave_2: url: jdbc:mysql://slave2:3306/db username: root password: 123456 strategy: com.baomidou.dynamic.datasource.strategy.LoadBalanceDynamicDataSourceStrategy然后在写操作上使用@DS("master"),读操作上使用@DS("slave"),组件会自动在slave_1和slave_2之间做负载均衡。
