信创迁移的第一道坎,不是 SQL 兼容
很多团队做信创替代,第一反应是去对 SQL 语法差异、改存储过程、调数据类型映射。这些确实是硬骨头,但往往不是第一个让你加班到凌晨的问题。
第一个让你头疼的,通常是连接池。
你的 Spring Boot 项目从 MySQL 迁移到国产数据库,JDBC 驱动换了,连接池参数是不是也得跟着改?答案是:必须改,而且要改对。直接沿用 HikariCP 默认的 MySQL 参数,上线三天内大概率会出现连接泄漏、Socket 超时或者事务死锁。
本文不讲宏观架构选型,只聊一件事:Spring Boot 项目接入达梦、GaussDB、金仓这三款国产数据库时,连接池和事务隔离该怎么配。
所有配置均来自生产环境实测,可以直接拿去用。
基础环境
| 项目 | 规格 |
|---|---|
| 框架 | Spring Boot 2.7 / 3.2 |
| JDK | 17 |
| ORM | MyBatis-Plus 3.5 |
| 连接池 | HikariCP 4.0(默认)/ Druid 1.2 |
| 数据库 | 达梦 DM8 / GaussDB 503 / KingbaseES V8R6 |
一、Maven 依赖:先过驱动这关
三款数据库的 JDBC 驱动都不在 Maven 中央仓库,需要手动安装到私服或本地仓库。
|
|
坑1:达梦的 Maven groupId 不同版本不一样。8.1.2.x 用
com.dameng,更早版本可能是com.dameng.database。以你拿到的 jar 包里的 pom.properties 为准。
坑2:GaussDB 有两条技术路线——基于 MySQL 协议的(华为云 RDS for GaussDB)和基于 openGauss/PostgreSQL 协议的。JDBC 驱动完全不同,别搞混了。本文讨论的是 openGauss 路线。
二、application.yml 全配置模板
达梦 DM8
|
|
关键 URL 参数说明:
| 参数 | 作用 | 推荐值 |
|---|---|---|
schema |
默认 schema | 你的业务 schema |
loginEncrypt |
登录加密(默认true) | false(内网环境) |
socketTimeout |
Socket 读超时(ms) | 60000 |
loginTimeout |
连接建立超时(ms) | 5000 |
compatibleMode |
兼容模式 | mysql / oracle |
batchNotOnCall |
批处理不走存储过程调用 | true |
坑3:
compatibleMode=mysql只影响 SQL 解析层面的兼容(比如支持 LIMIT、反引号),不改变底层协议。如果你的 SQL 用了 MySQL 特有函数(如IFNULL),还是得改成达梦的NVL。
华为 GaussDB(openGauss 路线)
|
|
关键 URL 参数说明:
| 参数 | 作用 | 推荐值 |
|---|---|---|
currentSchema |
默认 schema | public 或业务 schema |
connectTimeout |
连接建立超时(秒) | 10 |
socketTimeout |
Socket 读超时(秒) | 60 |
targetServerType |
主备模式选主库 | primary |
loadBalanceHosts |
负载均衡 | false(写场景) |
坑4:GaussDB 主备模式下,
targetServerType=primary确保写操作走主库。如果你设成any,读操作可能分配到备库,而备库有复制延迟,你的业务可能读到脏数据。
坑5:GaussDB 的
connectTimeout和socketTimeout单位是秒,不是毫秒。达梦的单位是毫秒。这个差异极其容易搞混。
人大金仓 KingbaseES V8R6
|
|
坑6:金仓默认端口是 54321,不是 PostgreSQL 的 5432。虽然金仓底层基于 PostgreSQL,但部署时端口经常不一样。
坑7:
escapeSyntaxCallMode=callIfNoReturn解决的是存储函数调用兼容问题。金仓对{call xxx()}和{? = call xxx()}的处理逻辑不同,这个参数让驱动自动选择正确的调用方式。不加的话,MyBatis 调用存储过程会报错。
三、连接池参数对比与选型
HikariCP vs Druid
| 维度 | HikariCP | Druid |
|---|---|---|
| 性能 | 极高(零锁设计) | 高(有锁竞争) |
| 监控 | 需集成 Micrometer | 自带 Web 监控面板 |
| 国产数据库适配 | 需手动调参 | 内置部分国产数据库方言 |
| SQL 防火墙 | 无 | 有(防 SQL 注入) |
| 连接泄漏检测 | leakDetectionThreshold |
removeAbandoned |
选型建议:
- 如果你的项目有运维团队能搭 Prometheus + Grafana → HikariCP(性能最优)
- 如果项目需要快速定位慢 SQL 和连接泄漏 → Druid(开箱即用的监控)
- 信创项目要过安全审查 → Druid(内置 SQL 防火墙是加分项)
连接池大小怎么定
很多团队直接用默认值(HikariCP 默认 maximumPoolSize=10)。这个值在开发环境够用,生产环境大概率不够。
经验公式:
|
|
但对于国产数据库,还需要考虑数据库服务端的最大连接数限制。三款数据库的默认值差异很大:
| 数据库 | 服务端默认最大连接数 | 建议单节点连接池上限 |
|---|---|---|
| 达梦 DM8 | 100 | 20~30 |
| GaussDB | 200(主备共享) | 20~40 |
| 金仓 V8R6 | 100 | 15~25 |
坑8:如果你的 Spring Boot 部署了3个实例,每个实例连接池 maximumPoolSize=20,那数据库端就是 60 个连接。别忘了加上其他服务、定时任务、监控探针的连接,很容易打满服务端的 max_connections。
四、事务隔离级别:最容易忽略的坑
Spring Boot 默认的事务隔离级别是 READ_COMMITTED(MySQL 的默认值)。但三款国产数据库的默认隔离级别不同:
| 数据库 | 默认隔离级别 | 与 MySQL 差异 |
|---|---|---|
| 达梦 DM8 | READ_COMMITTED | 一致 |
| GaussDB | READ_COMMITTED | 一致 |
| 金仓 V8R6 | READ_COMMITTED | 一致 |
看起来一致?别急。问题出在实现方式上。
达梦的 MVCC 行为差异
达梦的 READ_COMMITTED 在实现上更接近 Oracle——不加锁读,通过 Undo 段实现多版本并发控制。但有一个细节:
|
|
达梦的 FOR UPDATE 会对满足条件的行加排他锁,如果其他事务也在 SELECT FOR UPDATE 同一行,第二个事务会阻塞直到第一个事务提交或回滚。这和 MySQL 一致。
但达梦有一个特殊行为:如果 SELECT 的结果集在事务期间被其他事务修改,达梦可能会抛出 ORA-08177 类似的错误(在达梦里叫"串行化冲突")。MySQL 不会。
GaussDB 的 SSI 模式
GaussDB 支持 Serializable Snapshot Isolation (SSI),但默认不开。如果你的业务场景需要严格的可序列化隔离(比如金融交易),需要在 URL 里加参数:
|
|
但注意:SSI 模式下的性能损耗在 20%~40%,非必要不开。
金仓的 HOT 更新问题
金仓基于 PostgreSQL,存在 HOT(Heap-Only Tuple)更新机制。在高并发更新场景下,如果更新的行有索引且索引列没变化,金仓会走 HOT 路径避免索引更新。但如果索引列被改了,性能会骤降。
建议在金仓上避免在事务中频繁更新索引列,或者对高频更新的列考虑去掉索引。
Spring 事务配置模板
|
|
坑9:
@Transactional不加rollbackFor = Exception.class的话,Spring 默认只回滚RuntimeException。如果业务方法抛了IOException等 checked exception,事务不回滚,数据就脏了。这个坑不分国产数据库还是 MySQL,但信创项目因为测试覆盖率普遍不高,更容易漏掉。
五、连接保活与断线重连
国产数据库的连接被服务端主动断开的概率比 MySQL 高。原因通常是:
- 达梦的
MAX_SESSION_IDLE_TIME默认值较低 - GaussDB 主备切换时会断开所有连接
- 金仓的
tcp_keepalives_idle默认2小时
HikariCP 的保活配置
|
|
核心原则:HikariCP 的 max-lifetime 一定要比数据库服务端的连接超时时间短至少30秒。否则连接池以为连接还活着,数据库已经把它杀了,下一次使用就会报 Connection is not available。
达梦的特殊处理
达梦有一个 INI 参数 MAX_SESSION_IDLE_TIME,默认值可能是30分钟甚至更短。如果你的应用有低流量时段(比如凌晨),空闲连接很可能被达梦杀掉。
|
|
六、MyBatis-Plus 的方言适配
MyBatis-Plus 的分页插件需要指定数据库方言:
|
|
坑10:GaussDB 没有 MyBatis-Plus 的专用方言枚举值。用
DbType.POSTGRE_SQL代替,因为 GaussDB 的 SQL 语法和 PostgreSQL 高度兼容。但如果你用的是华为云 GaussDB for MySQL(MySQL 协议),那就用DbType.MYSQL。
七、一张配置对照表
把上面的所有配置汇总成一张表,方便直接对照使用:
| 配置项 | 达梦 DM8 | GaussDB (openGauss) | 金仓 V8R6 |
|---|---|---|---|
| 驱动类 | dm.jdbc.driver.DmDriver |
org.opengauss.Driver |
com.kingbase8.Driver |
| URL 前缀 | jdbc:dm:// |
jdbc:opengauss:// |
jdbc:kingbase8:// |
| 默认端口 | 5236 | 5432 | 54321 |
| 超时单位 | 毫秒 | 秒 | 秒 |
| 心跳SQL | SELECT 1 |
SELECT 1 |
SELECT 1 |
| MBP方言 | DbType.DM |
DbType.POSTGRE_SQL |
DbType.KINGBASE_ES |
| 建议连接池上限 | 20~30 | 20~40 | 15~25 |
| keepalive-time | 180000 | 300000 | 300000 |
| max-lifetime | 1200000 | 1800000 | 1800000 |
| 默认隔离级别 | READ_COMMITTED | READ_COMMITTED | READ_COMMITTED |
写在配置文件里
信创迁移不是"换个驱动就完事"。连接池参数、超时设置、事务隔离、方言适配,每一个环节都可能成为线上事故的导火索。
建议把上面这张对照表贴在项目组的知识库里,每接入一个新的国产数据库就对照检查一遍。与其上线后凌晨救火,不如上线前花两个小时把配置做对。
这些坑我们都踩过,你不必再踩一遍。