说起来,数据库迁移这事儿干过的人都懂------看着文档挺简单,真上手全是坑。尤其是从PostgreSQL迁到国产数据库,不是简单跑个工具就能搞定的事,字段类型、语法差异、索引策略、连接配置,哪一项没处理好都能让你在凌晨三点对着屏幕怀疑人生。
我最近刚完成一个项目的数据迁移,把PostgreSQL 12的业务库迁到了电科金仓KESV9,踩了不少坑。趁着还有记忆,把这套实战经验整理出来,给要做类似迁移的同行参考。
迁移前评估:别急着动手
很多人上来就开始跑迁移工具,结果导完发现一堆问题,又得重来。我的建议是先做兼容性评估,这一步至少能帮你预估30%的工作量。
电科金仓提供了KDMS评估工具,可以用命令行快速扫描源库,生成一份兼容性报告:
bash
# 评估PostgreSQL到金仓的兼容度
kmt-assess --source=postgresql://user:pass@192.168.1.100:5432/production \
--target=kingbase://user:pass@192.168.1.101:54321/mydb
跑完之后会生成类似这样的结果:
对象兼容率: 96.2% (表、视图、索引基本无问题)
语法兼容率: 89.7% (主要集中在函数和触发器)
预计需要手动处理: 23个对象
这里有个重要的经验:兼容率低于95%的项目,建议先把应用层代码适配做完再迁移数据,否则数据导进去发现逻辑跑不通,回头改起来成本更高。
类型映射:血的教训
PostgreSQL和电科金仓的数据类型并不是一一对应的,以下几个坑我真真切切踩过:
serial自增列 。PostgreSQL里直接写id SERIAL PRIMARY KEY,电科金仓得改成序列+默认值的方式:
sql
-- PostgreSQL原写法
CREATE TABLE users (
id SERIAL PRIMARY KEY,
name VARCHAR(100)
);
-- 电科金仓适配写法
CREATE SEQUENCE users_id_seq START 1;
CREATE TABLE users (
id INTEGER DEFAULT NEXTVAL('users_id_seq') PRIMARY KEY,
name VARCHAR(100)
);
text和varchar。PostgreSQL里text和varchar几乎没有区别,金仓虽然也支持text,但某些老版本在查询优化器处理上会有差异。建议统一用varchar,或者在建表时显式指定长度。
JSON处理。PostgreSQL的jsonb数据类型,金仓里对应的是json类型。函数调用语法也有差异:
sql
-- PostgreSQL
SELECT data->>'name' FROM users WHERE data @> '{"status":"active"}';
-- 金仓(等效写法)
SELECT data->>'name' FROM users WHERE data @? '$.status ? (@ == "active")';
迁移工具:KDTS实战
电科金仓官方提供的KDTS是我用下来最顺手的迁移工具,支持从PostgreSQL、MySQL、Oracle等多种数据库迁移到金仓。
启动服务
bash
# 进入KDTS安装目录
cd /opt/Kingbase/ES/V8/ClientTools/guitools/KDTS/KDTS-WEB
# 启动服务
./bin/startup.sh
启动成功后访问 http://localhost:54523,默认账密是 kingbase/kingbase。
配置数据源
在Web界面依次添加源库和目标库:
源库配置(PostgreSQL):
类型: PostgreSQL
主机: 192.168.1.100
端口: 5432
数据库: production
用户名: postgres
密码: your_password
目标库配置(金仓):
类型: KingbaseES V9
主机: 192.168.1.101
端口: 54321
数据库: targetdb
用户名: system
密码: your_password
创建迁移任务
新建迁移任务时,有几个选项要注意:
yaml
# KDTS任务配置示例
迁移对象:
- 表结构: 是
- 表数据: 是
- 主键: 是
- 索引: 是
- 外键: 是
对象过滤:
schema: public # 只迁移public模式
排除系统表: true
有个细节:源模式选了public,但目标模式下拉框里没public选项。这不是bug,金仓默认会导入到public模式下,直接点下一步就行。
迁移后验证
迁移完成后一定要做数据校验,光看日志显示成功不代表真的没问题:
sql
-- 1. 对比记录数
SELECT 'users' as tbl,
COUNT(*) as row_count
FROM public.users;
-- 2. 抽样校验数据内容
SELECT * FROM public.users
ORDER BY id
LIMIT 10 OFFSET RANDOM() * 1000;
-- 3. 验证索引是否正确创建
SELECT indexname, indexdef
FROM pg_indexes
WHERE tablename = 'users';
应用适配:JDBC驱动和连接配置
代码层面的改动不多,但有几处必须改:
驱动包替换:
xml
<!-- pom.xml: 移除PostgreSQL驱动 -->
<!-- <dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
</dependency> -->
<!-- 添加金仓驱动 -->
<dependency>
<groupId>cn.com.kingbase</groupId>
<artifactId>kingbase8</artifactId>
<version>8.6.0</version>
</dependency>
连接字符串修改:
yaml
# application.yml
spring:
datasource:
driver-class-name: com.kingbase8.Driver
url: jdbc:kingbase8://192.168.1.101:54321/targetdb?currentSchema=public
username: system
password: your_password
注意金仓默认端口是54321,不是PostgreSQL的5432。还有个参数currentSchema必须加上,否则默认搜索路径可能不是你预期的模式。
语法兼容:几个高频踩坑点
字符串函数差异 。PostgreSQL的substring(str from pos for len)语法,建议改成标准SQL的SUBSTR(str, pos, len):
sql
-- PostgreSQL
SELECT SUBSTRING(name FROM 1 FOR 10) FROM users;
-- 金仓(推荐写法)
SELECT SUBSTR(name, 1, 10) FROM users;
分页语法。LIMIT/OFFSET写法在金仓里完全兼容,但要注意某些框架生成的SQL写法可能有问题,建议用EXPLAIN先跑一下看看执行计划。
标识符引号。PostgreSQL用双引号包住保留字作为标识符,金仓同样支持,但如果遇到奇怪的报错,试着用单引号替代字符串值的引号。
总结:给同行的建议
整体迁移流程总结下来,有几点心得:
-
评估先行:不要相信宣传,要眼见为实,自己跑一遍评估工具,至少知道哪些地方要手动处理。
-
数据校验不能省:迁移评估工具显示成功不代表真的没问题,数据一致性校验必须做。
-
灰度迁移:生产环境建议先用双写验证一段时间,确认业务逻辑完全兼容后再切流量。
-
保留回滚能力:迁移前确保PostgreSQL端数据可以快速恢复,切换后发现问题能及时回退。
说实话,国产数据库发展到今天,基础能力已经不差了,但在细节打磨上还有提升空间。比如某些边缘语法的处理、文档的完整性等,都还有改进余地。不过对于信创合规要求下的迁移需求,金仓这套方案已经能cover住大多数场景,关键是迁移过程中的细心和耐心。
有问题欢迎评论区交流,迁移路上踩过的坑,多一个人知道就少一个人遭罪。