一、我是在 ruoyi-common-datasource 模块里,创建了一个 DatabaseIdConfig:

使用 MyBatis 自带的 VendorDatabaseIdProvider:把 数据库产品名 映射为 MyBatis 的 databaseId:MySQL → mysql,KingbaseES / PostgreSQL → kingbase(金仓基于 PG,所以两个都映射为 kingbase)Spring Boot 自动配置 MyBatis 时,会自动使用这个 DatabaseIdProvider。为了防止有些场景没正确设置 databaseId,又实现了一个 ApplicationListener<ApplicationReadyEvent>:应用启动完成后,遍历所有 SqlSessionFactory:如果 Configuration.getDatabaseId() 为空,就用 DatabaseIdProvider.getDatabaseId(dataSource) 手动算一遍并 setDatabaseId。日志里会输出每个 SqlSessionFactory 识别到的 databaseId,方便排查。

效果:

无论是 MySQL 还是金仓,只要 JDBC 能连上,MyBatis 都能统一得到 _databaseId = 'mysql' 或 _databaseId = 'kingbase',供 XML 里判断。


二、Mapper 层根据 _databaseId 写双分支 SQL

在 Mapper.xml 里,使用了 MyBatis 的 _databaseId 变量配合 <choose>/<when> 来做方言兼容。

主要几类差异:

1. 时间函数 / 日期计算差异

例如工单统计里“上周、本周”的时间区间:

  • MySQL 分支用 DATE_SUB、CURDATE()、WEEKDAY():

      <when test="_databaseId == 'mysql'">

          AND DATE(wp.appear_time) >= DATE_SUB(CURDATE(), INTERVAL WEEKDAY(CURDATE()) + 7 DAY)

          AND DATE(wp.appear_time) <= DATE_SUB(CURDATE(), INTERVAL WEEKDAY(CURDATE()) + 1 DAY)

      </when>

  • 金仓分支用 DATE_TRUNC('week', CURRENT_DATE) + INTERVAL:

      <otherwise>

          AND DATE(wp.appear_time) >= (DATE_TRUNC('week', CURRENT_DATE) + INTERVAL '1 day') - INTERVAL '7 days'

          AND DATE(wp.appear_time) <= (DATE_TRUNC('week', CURRENT_DATE) + INTERVAL '1 day') - INTERVAL '1 day'

      </otherwise>

2. 布尔 / TINYINT 存储差异
  • MySQL 下直接插入/更新 #{menuCheckStrictly}(Boolean 自动映射成 tinyint)。
  • 金仓下先用 CASE WHEN ... THEN 1 ELSE 0 END,再 CAST 成 SMALLINT:

      <choose>

        <when test="_databaseId == 'kingbase'">

          CAST(CASE WHEN #{menuCheckStrictly} THEN 1 ELSE 0 END AS SMALLINT),

        </when>

        <otherwise>

          #{menuCheckStrictly},

        </otherwise>

      </choose>

3. 日期时间函数差异(sysdate() vs CURRENT_TIMESTAMP)

创建时间、更新时间等字段:

  • MySQL 用 sysdate()。
  • 金仓用 CURRENT_TIMESTAMP:
4. 关键字/字段名差异

比如 from 等在 MySQL 里需要反引号,在金仓里可以直接用或用双引号,这些也通过 _databaseId == 'mysql' 做了分支处理。


三、使用方式:怎么切库而不改代码

基于这一整套设计,切换数据库只需要:

  • 在配置中心(如 ruoyi-system-dev.yml )里改:
  • driver-class-name(MySQL 或 Kingbase 驱动)
  • url(jdbc:mysql://... 或 jdbc:kingbase8://... / PG 协议)
  • 用户名、密码
  • 代码层 完全不需要改:
  • DatabaseIdProvider 会自动识别成 mysql 或 kingbase。
  • Mapper XML 自动走对应 <when test="_databaseId == 'xxx'"> 分支。

总结

现有 MySQL 项目只要按照此方式增加 Mapper 中的 kingbase 分支和一个公共 DatabaseIdConfig,就能做到“一套代码,双数据库”。

Logo

DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。

更多推荐