单文件 Java 工具(JDK 17 直接运行,无需构建)。结构走 SHOW CREATE TABLE 结构化解析生成达梦 DDL,数据走 JDBC 驱动层 ResultSet → PreparedStatement 批量直搬,全程零 SQL 文本转义(INSERT 转义是 dump 文本转换路线最脆弱的环节,本工具从驱动层消灭它)。
已在本项目测试库实测通过:15 表结构 + 1538 行数据 + 18 外键 + 全部唯一索引,行数/主键水位/大字段/全表指纹校验全部一致。
# JDK17 + 两个 JDBC 驱动(m2 仓库已有)
MYSQL_JAR=C:/Users/Administrator/.m2/repository/com/mysql/mysql-connector-j/8.4.0/mysql-connector-j-8.4.0.jar
DM_JAR=C:/Users/Administrator/.m2/repository/com/dameng/DmJdbcDriver18/8.1.3.62/DmJdbcDriver18-8.1.3.62.jar
cd backend-java/tools
java -Dfile.encoding=UTF-8 -cp "$MYSQL_JAR;$DM_JAR" DbMigrator.java migrate \
--source-url 'jdbc:mysql://源库:3306/dms?useSSL=false&characterEncoding=utf8' \
--source-user dms_app --source-pwd '密码' \
--target-url jdbc:dm://达梦库:5236 --target-user DMS --target-pwd '密码' \
--schema DMS_MIGTEST --create-schema --drop-existing
三种模式:
| 模式 | 说明 |
|---|---|
migrate |
建结构 + 搬数据 + 建外键 + 自动校验(行数 + 单列数值主键水位) |
verify |
只校验,不改动目标库 |
drop-schema |
只清空目标模式(先删全部外键再删表,可反复重跑) |
常用参数:--tables a,b 只迁指定表;--exclude c 排除表;--batch 1000 批大小;--no-verify 跳过校验;--err-log FILE 坏行日志(默认 migrate_errors.log)。
Windows 注意:若密码含 !,在部分 shell(git bash 传参给 java.exe)下引号包裹反而会被转义成 \!,此时密码不加引号裸写即可;URL 含 & 则必须加引号。
verify 跑一遍目标连通;确认源库为 MySQL 8.x。migrate --create-schema --drop-existing(幂等,可反复重跑)。0021(缺 0022 登录锁定的 failed_login_count/locked_until 列)。Flyway 在达梦默认禁用,需手工执行 backend-java/src/main/resources/db/migration/V7__login_lockout.sql(幂等),并同步更新 alembic_version/flyway_schema_history 中该库对应的版本记录。.env 的 DMS_DATABASE_URL 指向达梦(jdbc:dm 或 dm+dmPython 形式均可,Java 侧自动互转),重启服务。.env 切回 MySQL URL 即可(迁移只写目标库,不动源库)。| MySQL | 达梦处理 |
|---|---|
AUTO_INCREMENT |
IDENTITY(1,1);数据期自动 SET IDENTITY_INSERT ON/OFF + 显式列清单 |
生成列 IF(cond,1,NULL) VIRTUAL |
TINYINT AS (CASE WHEN cond THEN 1 END) |
| 含生成列的内联 UNIQUE(-2034) | 后置 CREATE UNIQUE INDEX |
| NULL 判重语义差异 | MySQL 任一键列 NULL 即不判重;达梦(Oracle 语义)仅全 NULL 键不判重。对齐方式:全部键成分套同一守卫 CASE,非判重行整体置全 NULL 键 |
| 单标记生成列唯一键(全局唯一默认项) | 单成分 CASE 守卫唯一索引 |
ON DELETE RESTRICT |
剥离(默认 NO ACTION 语义等价) |
| FULLTEXT/SPATIAL/前缀索引 | 跳过/整列降级,输出 WARN |
datetime(n)/timestamp(n) |
TIMESTAMP(n) |
text/mediumtext/longtext/json |
TEXT/CLOB/TEXT |
tinyint(n) |
TINYINT(n 为显示宽度不代表值域);unsigned 才升 SMALLINT |
enum/set |
VARCHAR(255) + 告警(枚举约束不迁移,靠 CHECK 或应用层) |
| 保留字标识符 | 统一大写,保留字加双引号 |
WHERE pk > ? ORDER BY pk LIMIT n 窗口分页(内存友好);复合/无主键表整表加载并 WARN。--err-log 不中断整体(唯一键冲突的行会明确记录 pk)。非单列数值主键,整表加载:版本表/字典表无碍;业务大表出现时评估内存或改用 --tables 分批。多列唯一键含可空列…NULL组合重复的数据将冲突:源库若真存在多行「部分 NULL」重复键(MySQL 合法、达梦冲突),需先在源库清洗,或接受该约束在达梦更严格。UNSIGNED 不被达梦支持:值域超 INT/BIGINT 上限的数据不会存在时无碍;tinyint/smallint unsigned 已自动升档。