简介:面向国产化数据库适配需求,这份资源配置人大金仓(KingbaseES)环境下的 Java 配套文件,适合正在做信创迁移、数据库国产化替换的开发者参考。资源共4个文件,含 zip 打包文件、txt 说明文档与 SQL 脚本,整体大小约 242.67MB。说明文档用于快速梳理适配思路与注意事项,SQL 脚本提供建表、初始化及迁移验证所需的语句,可帮助开发者在 Java 业务中减少数据库差异带来的改造工作量。当前已有118人学习下载,对需要熟悉人大金仓适配流程、排查常见兼容问题的技术人员有直接参考价值。通过资源包能了解国产化环境下各类文件如何组织与配合,避免从零摸索数据库差异,快速在项目中完成基础适配验证,也为后续扩展其他国产数据库迁移提供可复用的操作参照。
1. 适配国产化人大金仓文件:为什么 80% 的坑都在“文件之外”
“适配国产化人大金仓文件”是信创项目里最容易被低估的一步。多数人接到任务后第一反应是:把 Oracle 或 MySQL 的数据文件导出,再导进 KingbaseES 就完事。真跑起来才发现,难的不是文件本身,而是驱动类名、SQL 方言、字符集、权限和连接池参数。本文按我自己的迁移顺序,把 KingbaseES(人大金仓)在银河麒麟环境下的适配路径拆开讲:先定兼容基线,再做应用和数据的迁移,最后落到备份文件和上线验证。目标读者是两类人:要把存量 Oracle/MySQL 业务迁到金仓的应用开发,以及负责国产化改造落地的运维。读完这套东西,你能得到一份可以直接照着执行的最小适配清单,也能少走别人踩了三天的弯路。
2. 先定兼容基线再做适配:版本、部署形态与最小环境清单
2.1 三个决定:部署形态、兼容模式、运行身份
我在评估金仓适配工作量时,通常先逼客户回答三个问题,这三个问题直接影响后面所有步骤。
第一个是部署形态。常见做法有三种:物理机、虚拟机、容器。很多人为了快速验证语法兼容性,直接拉一个人大金仓数据库 docker 镜像起来跑业务 SQL,这是合理的试用路径。但生产环境我不建议把数据目录放在容器可写层,因为容器重建、镜像更新都可能把数据文件冲掉。生产要么用物理机,要么用虚拟机挂独立数据盘,数据目录单独规划。
第二个是兼容模式。KingbaseES 同时兼容 Oracle 和 PostgreSQL 两套方言,这个选择要在初始化或建库阶段决定,后期切换成本高。如果源系统是 Oracle,选 Oracle 兼容模式;如果源系统是 MySQL,但存储过程写得少,用 PostgreSQL 兼容模式通常更干净。关键是这个决定要先做,别等程序跑起来报语法错误再回头改。
第三个是运行身份。金仓数据库进程不允许以 root 身份长期运行,需要单独建一个系统用户。很多第一次接触国产化数据库的人在这里翻车:用 root 初始化,启动时报权限错误,或者数据文件属主变成 root,后面备份、归档全部踩坑。
提示:这三个问题不解决,后面的 JDBC 驱动和 SQL 改写做得再对,也会被环境问题拖住。
2.2 最小环境清单:银河麒麟上的文件与依赖
先给一份我常用的最小环境清单,表格里的每一项都有明确理由。
| 项目 | 推荐配置 | 原因 |
|---|---|---|
| 操作系统 | 银河麒麟 V10 SP1/SP2 | 信创项目最常见基线 |
| CPU 架构 | x86_64 或 aarch64 | 安装包和 JDK 必须匹配,别再混装 |
| 内存 | 4C8G 起步,生产建议 16C32G | 编译执行计划和排序都要内存 |
| 数据盘 | /data 单独挂载,ext4 或 xfs | 避免系统盘和数据文件抢 I/O |
| 运行用户 | kingbase | 数据库进程安全要求 |
| JDK | OpenJDK 8 或 11 | 需匹配 CPU 架构,aarch64 和 x86_64 的包不一样 |
| 基础依赖 | libaio、numactl、unixODBC | 数据库运行和 ODBC 访问都要用 |
这里要单独说“文件”这个词。适配工作接触的文件不只是业务数据文件,还包括安装目录下的配置文件:KingbaseES 实例级配置文件、客户端认证文件、日志目录。在麒麟系统上,很多人下载离线依赖包时没注意架构,把 x86_64 的 rpm 传到鲲鹏机器上装,结果依赖检测直接失败。正确的做法是安装前先确认arch命令输出,再下载对应架构的包。这一步属于“适配银河麒麟系统应用软件下载列表”里的第一道坑。
2.3 初始化实例:initdb 与 sys_ctl 的基础命令和参数说明
环境准备好后,初始化实例是整个适配动作的起点。下面这套命令是我验证过多次的最小流程,以一个数据目录/data/kingbase/data为例。
# 创建系统用户,注意不能用 root 直接跑数据库 useradd -m kingbase # 数据目录单独挂载,避免和系统盘抢 I/O mkdir -p /data/kingbase/data chown -R kingbase:kingbase /data/kingbase # 初始化数据库实例,重点看 encoding 和 locale su - kingbase -c "/opt/kingbase/ES/V8/install/bin/initdb \ -D /data/kingbase/data \ -U system \ --encoding=UTF8 \ --locale=C \ -E UTF8" # 启动实例,日志写到独立目录 su - kingbase -c "/opt/kingbase/ES/V8/install/bin/sys_ctl \ -D /data/kingbase/data \ -l /data/kingbase/log/startup.log \ start"这里面有几个参数值得展开。-U system是金仓默认的超级用户,相当于 Oracle 的 sys;--encoding=UTF8和-E UTF8共同保证数据库内部字符集是 UTF8,这直接影响后续导入中文数据是否乱码;--locale=C我建议固定,因为某些 Linux 发行版默认 locale 可能导致排序结果和源库不一致,还会在日志里刷警告。
启动后别急着连,先确认端口状态。金仓默认端口是 54321,和 PostgreSQL 的 5432 不同,改应用配置的时候容易忘。
ss -lntp | grep 54321如果端口没起来,去看启动日志文件startup.log最后 50 行,90% 的问题无非三种:端口被占、数据目录权限不对、初始化参数冲突。日志文件里写得很直白,比任何诊断工具都可靠。
到这里,环境基线就立住了。后面所有驱动替换、SQL 改写、迁移和备份,都跑在这套基线之上。
3. 国产化迁移的驱动替换与 SQL 方言校正:从 Oracle/MySQL 到 KingbaseES
3.1 JDBC 驱动替换:四个要改的位置
应用连数据库的第一步是换驱动。很多项目的报错都集中在“找不到类”或“URL 格式不对”,本质上是只改了依赖,没有同步改连接串和驱动类名。我一般会把下面四个位置一起改,避免漏项。
第一个是构建依赖。假设原来用的是 Oracle 的 ojdbc,或者 MySQL 的 connector,要换成金仓的 JDBC 驱动。Maven 里的坐标写法如下。
<dependency> <groupId>com.kingbase</groupId> <artifactId>kingbase8</artifactId> <version>以官方发布版本为准</version> </dependency>第二个是驱动类名。改成com.kingbase8.Driver,不再用oracle.jdbc.OracleDriver或com.mysql.cj.jdbc.Driver。
第三个是连接 URL。格式是jdbc:kingbase8://主机IP:54321/数据库名,还可以带参数。下面这段 Spring Boot 的配置是一个常见写法。
spring: datasource: driver-class-name: com.kingbase8.Driver url: jdbc:kingbase8://192.168.1.10:54321/appdb?currentSchema=app&characterEncoding=UTF-8 username: app_user password: App@2025 hikari: connection-test-query: select 1 maximum-pool-size: 20第四个是连接池验证语句。HikariCP 默认验证连接用select 1,在 Oracle 下也能跑,但在某些兼容模式下最好显式写select 1,避免连接池误判连接失效。currentSchema=app这个参数要重点说:它决定了会话默认的 schema 搜索路径,应用如果习惯不写 schema 前缀,必须通过这个参数把业务 schema 指定清楚,否则会去 public 里找表,结果全是表不存在。
3.2 建库建用户与权限绑定:别用超级用户跑业务
驱动换好之后,数据库侧要建业务用户和业务库。这里的基本原则是:业务连接永远不用 system 超级用户,否则权限审计和后续回收都会很被动。
CREATE USER app_user WITH PASSWORD 'App@2025' CONNECTION LIMIT 50; CREATE DATABASE appdb OWNER app_user ENCODING 'UTF8' TEMPLATE template0; GRANT CONNECT, TEMPORARY ON DATABASE appdb TO app_user; -- 切换到业务库后创建业务 schema \c appdb CREATE SCHEMA IF NOT EXISTS app; ALTER USER app_user SET search_path TO app, public;TEMPLATE template0这一句容易被忽略。默认新建库用的是 template1,如果 template1 里被塞过额外对象或非 UTF8 排序规则,新库会被一起传染。search_path的设置解决的是对象解析顺序问题,把业务 schema 放在 public 前面,避免应用查错表。
3.3 SQL 方言差异:从 Oracle/MySQL 迁来最容易报错的地方
SQL 方言校正是我见过的工作量最大的部分。下面的对照表是迁移时最常改的几类写法。
| Oracle / MySQL 写法 | KingbaseES 推荐写法 | 说明 |
|---|---|---|
WHERE ROWNUM <= 10 | LIMIT 10 | Oracle 兼容模式可跑 ROWNUM,PG 模式不行 |
NVL(a, 0) | COALESCE(a, 0) | 两个数据库迁移过来都通用 |
DECODE(a, 1, 'x', 'y') | CASE WHEN a = 1 THEN 'x' ELSE 'y' END | 标准 SQL 可移植性最好 |
SYSDATE | CURRENT_TIMESTAMP | 金仓里也有对应函数,但标准写法更稳 |
| 字符串拼接用 ` | ` |
在 MyBatis 的 XML 里翻车最多的场景是分页。Oracle 习惯写ROWNUM,MySQL 习惯写LIMIT,迁到金仓后如果开的是 PostgreSQL 兼容模式,ROWNUM直接不认。下面这段是一个改写后的分页查询。
<select id="queryPage" resultType="map"> SELECT id, COALESCE(nickname, '') AS nickname FROM app_user_info WHERE status = #{status} ORDER BY id LIMIT #{limit} OFFSET #{offset} </select>这里要特别注意#{}和${}的区别。#{}是预编译参数,不会产生 SQL 注入风险;${}是字符串拼接,只应该用于表名、列名这种结构场景。很多迁移项目为了省事,把过去写死的分页参数直接拼进去,结果金仓的预编译检查比 MySQL 严格,运行时直接报语法错误。
4. 数据特征适配与存量迁移:KDTS 参数和五条避坑记录
4.1 迁移前先做数据特征适配:用统计结果决定类型映射
存量数据迁移的第一步不是导文件,而是先摸清源库的数据特征。常见做法是写一段统计 SQL,把目标表的行数、空值率、字段最大长度跑出来,再决定类型映射。这一步我称之为“数据特征适配”,不做的话,VARCHAR2 字段长度设错了,导入到一半才发现超长。
SELECT MAX(LENGTH(nickname)) AS max_nickname_len, COUNT(*) AS total_rows, COUNT(nickname) AS not_null_rows, COUNT(DISTINCT nickname) AS distinct_cnt FROM app_user_info;MAX(LENGTH(...))给的是实际最大长度,不是定义长度。很多 Oracle 表把VARCHAR2(4000)定义得很吓人,实际数据最长只有 200 字符,金仓里建表就可以收敛到VARCHAR(256),索引大小和查询性能都会更好。COUNT(DISTINCT ...)用来估算重复度,决定要不要在目标表上建唯一索引。
特征确认后,再使用金仓官方的数据迁移工具 KDTS 做存量搬迁。KDTS 作为国产化工具,支持从 Oracle/MySQL/SQL Server 迁到 KingbaseES,图形界面和命令行都可以。关键是几个迁移参数,下面是一个任务配置文件的常见形态。
{ "source": { "type": "oracle", "url": "jdbc:oracle:thin:@//192.168.1.20:1521/ORCL", "user": "mig_user" }, "target": { "type": "kingbase", "url": "jdbc:kingbase8://127.0.0.1:54321/appdb", "user": "app_user" }, "option": { "batchSize": 500, "fetchSize": 200, "parallel": 4, "dropTarget": false, "convertLOBMode": "file", "convertEmptyStringToNull": false } }batchSize控制每次批量写入的条数,500 是兼顾内存和提交频率的保守值;fetchSize控制从源端一次抓取的行数,源端是 Oracle 时这个值太大会吃满网络和内存;parallel是并行度,建议按源端 CPU 核数的一半起步,别一上来就开 16,容易把源库打挂。convertLOBMode设置为file会把 CLOB/BLOB 拆到文件,再以文件方式导入目标端,避免大字段挤爆单个事务。convertEmptyStringToNull建议保持false,Oracle 里空字符串和 NULL 是同义的,但业务经常需要区分,保持原样迁移更安全。
4.2 避坑记录:迁移失败的五种典型现象与解法
这一节写我自己经历过的五条踩坑记录,每条都按“现象 → 原因 → 解决”说。
第一条:迁移到一半连接中断,日志报Connection reset。现象是表结构全建完了,数据倒到某个大表时报连接重置,任务失败。原因通常是源端空闲超时,或者fetchSize设置得太大,加上中间有防火墙拦截长时间空闲连接。解决方法是给源连接配置 keepAlive,把fetchSize从 5000 降到 200,同时在数据库和应用两侧把 TCP 空闲超时调长。
第二条:目标表行数比源表少了几千行。现象是迁移任务显示成功,但两张表count(*)对不上。原因多半是源端表上有触发器,迁移工具用 JDBC 读取时触发了触发器产生额外操作;或者是目标表存在主键冲突被工具默认跳过。解决方法是迁移前先对比源和目标的主键最大值,并打开迁移工具的冲突日志,把跳过记录单独导出检查。只信迁移工具的“成功”标志是不行的,必须用行数核对兜底。
第三条:导入后中文全部变成问号。现象是源端查出来正常,导进金仓后所有中文字段变成?。原因是源端连接字符集没设置成 UTF8,或者客户端的 NLS 环境变量不是 UTF8。解决方法是源连接串里显式加characterEncoding=UTF-8,同时确认金仓库本身是 UTF8 编码,也就是第 2 章里initdb阶段那两个编码参数没填错。
第四条:时间字段读写差异,DATE 类型丢失时间部分。现象是 Oracle 的DATE字段迁移后,应用查询时只显示日期没有时分秒。原因是金仓的DATE类型行为和 Oracle 不完全一致,Oracle 的DATE带时间,而金仓的DATE更接近“日历日期”。解决方法是迁移映射时把 Oracle 的DATE定义为TIMESTAMP,并在应用代码里把对应的实体类型从java.sql.Date改成java.sql.Timestamp。
第五条:迁移后自增序列错位,新插入数据主键重复。现象是应用上线后第一次插入就报唯一约束冲突。原因是源端序列的currval没有同步到金仓,目标序列从 1 开始,而表里已有数据的主键可能已经到 5000。解决方法是在迁移完大表后,手动重置序列到MAX(id)+1。
SELECT setval( pg_get_serial_sequence('app_user_info', 'id'), (SELECT COALESCE(MAX(id), 1) + 1 FROM app_user_info) );5. 麒麟系统上的信创适配与安全管理:文件权限、系统参数与备份验证
5.1 数据文件与日志文件分开:内核参数和进程文件句柄
数据库跑起来只是第一步,在麒麟系统上做生产适配,文件层面的规划比软件安装更要紧。我的基本原则是:数据文件、日志文件、归档文件分三个目录,避免一个盘写满把数据库拖死。
mkdir -p /data/kingbase/data mkdir -p /data/kingbase/log mkdir -p /data/kingbase/archive chown -R kingbase:kingbase /data/kingbase # 内核参数,写入 /etc/sysctl.conf vm.swappiness = 10 vm.dirty_ratio = 20 fs.file-max = 655360 # 进程文件句柄限制 cat >> /etc/security/limits.conf <<'EOF' kingbase soft nofile 65535 kingbase hard nofile 65535 kingbase soft nproc 65535 kingbase hard nproc 65535 EOF sysctl -pvm.swappiness设置为 10 是让内存尽量少做 swap 交换,数据库进程的访问模式是随机读多,swap 会放大延迟。vm.dirty_ratio限制脏页占内存比例,避免一次刷盘风暴把 I/O 打满。fs.file-max和nofile是给数据库进程开足够多的文件句柄,金仓实例在跑大量并发查询时会同时打开很多文件,默认 1024 完全不够。
5.2 关键配置文件参数:从默认值改成生产值
金仓的主配置文件在数据目录下,不同版本文件名略有不同,但内容形式和 PostgreSQL 很像。下面这几个参数是我每次必调的。
| 参数 | 推荐值 | 调整理由 |
|---|---|---|
shared_buffers | 物理内存的 25% | 默认值太小,缓存命中率上不去 |
work_mem | 8MB 起步 | 排序和哈希 JOIN 的内存上限 |
max_connections | 按连接池峰值加 30% | 设太大反而浪费内存 |
archive_mode | on | 开启后才有归档文件可恢复 |
log_min_duration_statement | 500ms | 慢查询日志文件从这里开始记 |
修改方式可以直接用ALTER SYSTEM,和 PostgreSQL 的体验一致。
ALTER SYSTEM SET shared_buffers = '2GB'; ALTER SYSTEM SET work_mem = '16MB'; ALTER SYSTEM SET max_connections = '300'; ALTER SYSTEM SET archive_mode = 'on'; ALTER SYSTEM SET log_min_duration_statement = '500ms';执行后需要重载配置才生效。金仓在 PostgreSQL 兼容模式下可以用SELECT pg_reload_conf();,部分版本也提供sys_reload_conf()。这两个函数在重载后返回 true,不用重启实例。
备份文件方面,金仓自带的物理备份工具通常以脚本形式提供,比如sys_backup.sh。具体参数以安装目录下--help输出为准,我不在这里写死。更通用且优先推荐的方式是:归档开启后,把归档目录定期复制到异地,再加上数据目录的文件系统快照。下面是一个简单的归档复制脚本思路。
# 把当天的归档文件同步到备份盘,保留 30 天 find /data/kingbase/archive -type f -name "*.log" -mtime +30 -delete cp -a /data/kingbase/archive /data/backup/archive_$(date +%F)5.3 上线前验证:执行计划、慢查询与一致性核对
验收阶段,我会在麒麟环境上做三件事:看慢查询日志是否正常输出、检查表膨胀情况、对比原系统与目标库的核心 SQL 执行计划。
慢查询日志先打开并确认日志文件路径,免得上线后才发现日志没写。
ALTER SYSTEM SET log_directory = '/data/kingbase/log'; ALTER SYSTEM SET log_filename = 'slowlog-%Y%m%d.log';表膨胀检查用系统视图。长期频繁更新和删除后,死元组占比过高会导致查询变慢,而且让数据文件异常膨胀。
SELECT schemaname, relname, n_live_tup, n_dead_tup, pg_size_pretty(pg_total_relation_size(relid)) AS total_size FROM pg_stat_user_tables WHERE n_dead_tup > 10000 ORDER BY n_dead_tup DESC LIMIT 10;一致性核对不能只靠count(*)。我在实践中会把原系统的核心交易 SQL 原样拿出来,在源库和目标库分别执行,对比结果集的行数和关键字段的校验和。下面的命令用金仓自带的 ksql 导出目标端结果,再和源端导出文件做 diff。
/opt/kingbase/ES/V8/install/bin/ksql \ -h 127.0.0.1 -p 54321 -U app_user -d appdb \ -c "SELECT id, status, amount FROM orders WHERE create_time >= '2025-01-01' ORDER BY id" \ -o /tmp/orders_target.txt对比文件时注意排序字段要一致,ORDER BY id能保证行的输出顺序稳定,否则diff会输出一堆没有意义的顺序差异。
6. 适配验证技巧:用 Top SQL 回归矩阵判定能否上线
最后一关是验证适配是否真的完成。我的判断标准不是“数据库能启动”,而是“原系统的 Top SQL 在目标库跑完一遍,执行计划和行数都对得上”。
具体做法是分三步。第一步,从原系统的慢查询日志或监控平台里拉出 Top 30 的 SQL,去掉具体参数值,做成一个参数化的 SQL 回归脚本,按业务模块分文件存放。第二步,在目标库打开慢语句自动记录,让回归脚本跑一遍,把金仓的慢日志文件当作“差分依据”。第三步,逐条对比执行计划和返回行数:行数不一致说明数据迁移有问题,执行计划出现全表扫描说明索引没建对或统计信息没收集。
开启自动记录可以用金仓对 PostgreSQL 兼容的auto_explain扩展。
LOAD 'auto_explain'; SET auto_explain.log_min_duration = '200ms'; SET auto_explain.log_analyze = on;log_min_duration设置成 200ms,意思是超过 200ms 的 SQL 会被自动记录,带上真实的执行计划和耗时;log_analyze = on会在日志里输出实际执行时间和行数。跑完回归脚本后,去日志文件里搜duration,低于你预期的 SQL 直接划掉,高于预期且执行计划里出现Seq Scan的,逐条回来看索引。
我踩过的一次教训是:迁移完只验证了启动和简单查询,没跑慢 SQL 回归。上线第一晚,一条 2000 万行事实表的大 JOIN 把生产库拖死,执行计划里两个表全是全表扫描,而原 Oracle 库里是走索引的嵌套循环。后来我把“Top SQL 回归矩阵+执行计划比对”写进了所有适配项目的验收清单,再没出过同类事故。这个习惯坚持到现在,希望帮到你。
本文还有配套的精品资源,点击获取