达梦数据库部署与 MySQL 迁移

需要用达梦数据库(DM8)替换 MySQL 作为平台元数据库时,如何部署达梦、配置客户端、把 MySQL 建表语句迁移到达梦

04-运维管理 / 元数据库
达梦达梦数据库DM8DMdamengdmPythondmSQLAlchemy国产数据库信创兼容模式COMPATIBLE_MODELENGTH_IN_CHARDM_SERVICEMySQL迁移DDL转换to_dm.py

达梦数据库(DM8)部署与 MySQL 迁移

本文覆盖两件事:

  1. 部署——用 Docker(本地或阿里云 ECS)跑起一个达梦 DM8 实例,并完成兼容模式、客户端驱动、连通性配置;
  2. MySQL 迁移到达梦——把平台原有的 MySQL 建表 DDL 通过正则批量转换成达梦 SQL,并用脚本灌库。

平台的元数据库连接统一通过 DM_SERVICE 环境变量配置,URI 形如 dm+dmPython://SYSDBA:<密码>@<host>:<port>?schema=kubeflow (见 install/docker/docker-compose.yml:57myapp/config.py:484)。 三类元数据库(MySQL / PostgreSQL / 达梦)的总体选型与切换说明见本段「元数据库配置.md」。


一、部署

推荐两种方式,生产优先用阿里云上常驻实例:阿里云上的参数已调优、性能好,部署完只要给服务器开外网 IP、安全组放开端口即可,不建议用本地自建实例顶生产。

1.1 本地 Docker 运行(测试用)

容器内端口固定为 5236不能改(参考 https://blog.csdn.net/chou342175867/article/details/145902563 )。对外可映射成任意 NodePort,下例映射到 30226

# 清理旧数据与旧容器
rm -rf /opt/data
docker rm dm8_test -f

# 启动 DM8(容器内 5236 -> 宿主 30226)
docker run -d -p 30226:5236 --restart=always --name=dm8_test --privileged=true \
  -v /opt/data:/opt/dmdbms/data \
  -e LD_LIBRARY_PATH=/opt/dmdbms/bin \
  -e PAGE_SIZE=16 -e EXTENT_SIZE=32 -e LOG_SIZE=1024 -e UNICODE_FLAG=1 \
  -e INSTANCE_NAME=dm8_test \
  ccr.ccs.tencentyun.com/cube-studio/dm8:dm8_20250206_rev257733_x86_rh6_64

1.2 阿里云上运行(生产)

阿里云镜像启动时直接挂载配置文件会失败,只能起来后再进容器改(见下文兼容模式)。

docker run -d -p 30226:5236 --restart=always --name=dm8_test --privileged=true \
  -v /opt/data:/opt/dmdbms/data \
  -e SYSDBA_PWD=19910101a \
  -e COMPATIBLE_MODE=4 \
  -e LD_LIBRARY_PATH=/opt/dmdbms/bin \
  -e PAGE_SIZE=16 -e EXTENT_SIZE=32 -e LOG_SIZE=1024 -e UNICODE_FLAG=1 \
  -e INSTANCE_NAME=dm8_test \
  -e PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin \
  -e CASE_SENSITIVE=0 -e LENGTH_IN_CHAR=0 -e BUFFER=30000 -e MODE=dmsingle \
  -e CHG_PASSWD=dameng777 -e DM_USER_PWD=dameng777 -e BLANK_PAD_MODE=0 \
  -e LANG=en_US.UTF-8 \
  ccr.ccs.tencentyun.com/cube-studio/dm8:dm8_20241022_rev244896_x86_rh6_64 /opt/startup.sh

常用启动参数说明:

环境变量 含义
SYSDBA_PWD / CHG_PASSWD / DM_USER_PWD SYSDBA / 修改后口令 / 业务用户口令
COMPATIBLE_MODE=4 兼容模式,4 为兼容 MySQL(迁移 MySQL DDL 必须开)
CASE_SENSITIVE=0 大小写不敏感(对象名不区分大小写)
LENGTH_IN_CHAR=0 / 1 varchar 长度按字节(0)还是按字符(1)计
PAGE_SIZE / EXTENT_SIZE / LOG_SIZE / BUFFER 页大小/簇大小/日志大小/缓冲,性能相关
UNICODE_FLAG=1 启用 Unicode
MODE=dmsingle 单机模式

注意:源 install/kubernetes/mysql/dm/kubeflow/readme.md:10 的阿里云示例里 -e COMPATIBLE_MODE=4 写了两次,是冗余笔误(已核对源文件),本文已合并为一个,效果不变。

1.3 兼容模式(进容器改 dm.ini)

如果启动时没设或要调整兼容模式,进容器改配置文件后重启:

docker exec -it dm8_test /bin/bash
vi /opt/dmdbms/data/DAMENG/dm.ini
# 修改/确认以下两项
COMPATIBLE_MODE = 4
LENGTH_IN_CHAR = 1        # 或者 NVARCHAR_LENGTH_IN_CHAR = 1
docker restart dm8_test

1.4 查看日志与口令

docker logs -f dm8_test                 # 看日志里是否 success
docker inspect dm8_test | grep PWD      # 注意:口令可能被改写,例如变成 SYSDBA_dm001

进容器用 disql 连:

docker exec -it dm8_test bash
source /etc/profile
cd /opt/dmdbms/bin/
./disql SYSDBA/SYSDBA_dm001            # 用 docker inspect 看到的真实口令

1.5 客户端驱动安装

平台后端通过 dm+dmPython 方言连接达梦,需要两个 Python 包:

平台镜像内版本(以 install/docker/requirements.txt 为准)
dmPython 2.5.30requirements.txt:64,达梦驱动)
dmSQLAlchemy 1.4.46requirements.txt:65,达梦 SQLAlchemy 方言)

安装方式:

# Linux(有 wheel,直接 pip)
pip install dmPython==2.5.30
pip install dmSQLAlchemy==1.4.46

# 其他平台(无 wheel,源码安装)
# 1) 到 https://eco.dameng.com/download/ 下载“达梦 Python 接口源码”
# 2) dmPython:在解压出的 dmPython 目录下执行  python setup.py install
# 3) dmSQLAlchemy:在 dmSQLAlchemy/dmSQLAlchemy1.4 目录下执行  python setup.py install

注意:源 readme.md:32 写的是 pip install dmSQLAlchemy==1.4.39,而平台镜像 install/docker/requirements.txt:65 钉的是 1.4.46(已核对)。本文以 requirements.txt 为准写成 1.4.46,与服务端版本保持一致。

注:PC(非 Linux)上 dmPython==2.5.30 没有 wheel 装不上。不需要达梦的开发者可临时绕过(见 install/docker/README.md:144):

grep -vE "^(dmPython|dmSQLAlchemy)" install/docker/requirements.txt > /tmp/req.txt
pip install -r /tmp/req.txt

1.6 连通性测试(DBeaver / disql)

用 DBeaver 等客户端连上后,建 schema、建测试表验证:

create schema KUBEFLOW AUTHORIZATION SYSDBA;

CREATE TABLE KUBEFLOW.ACCOUNTS (
    ACCOUNT_ID   INT PRIMARY KEY,
    ACCOUNT_NAME VARCHAR(100),
    BALANCE      DECIMAL(15,2)
);

注意 schema 大小写:readme.md 用大写 KUBEFLOW 建 schema,而平台连接串 docker-compose.yml:57 用的是小写 schema=kubeflow,迁移脚本 to_dm.md 也以小写 "kubeflow" 建 schema。配合启动参数 CASE_SENSITIVE=0(大小写不敏感)时二者等价;若实例区分大小写,务必让 schema 名与 DM_SERVICE 里的 schema= 完全一致。

1.7 平台侧行为差异(重要)

达梦作为元数据库时,平台不走 Alembic 迁移,而是用 db.create_all() 直接建表:

  • myapp/config.py:484-488:检测到 DM_SERVICE 后清空 migrations/versions 目录;
  • install/docker/entrypoint.sh:25-28:仅当 DM_SERVICE 为空时才执行 myapp db upgrade;达梦走 myapp/create_db.py 里的 db.create_all() 建表。

这也是为什么从 MySQL 迁移到达梦时,需要手工把 DDL 转换好(下一节),而不是依赖迁移文件。


二、MySQL 迁移到达梦

思路:把平台原有的 MySQL 建表脚本(kubeflow.sql)用编辑器/IDE 的正则替换,按下列规则批量改写成达梦语法,再用 to_dm.py 灌进达梦。涉及文件都在 install/kubernetes/mysql/dm/kubeflow/ 目录下(kubeflow.sql 建表、data.sql 初始数据、to_dm.py 执行器)。

2.1 正则批量转换规则

按顺序在编辑器里做正则「查找→替换」($1/$2 为捕获组):

清理无关语句与注释

查找(正则) 替换为
^SET.* 开头的行 删除
^DROP.* 开头的行 删除
`(反引号) "(双引号)
BEGIN;
COMMIT;
INSERT INTO.*
^--.*(行注释)
COMMENT.*?,\n ,\n

类型与子句改写

查找(正则) 替换为
ENGINE=InnoD.* STORAGE(ON "MAIN", CLUSTERBTR) ;
AUTO_INCREMENT IDENTITY(1,1)
UNIQUE KEY "(.*?)" CONSTRAINT TABLE1_$1 UNIQUE
COLLATE utf8mb4_general_ci
tinyint(1) TINYINT
mediumtext CLOB
datetime DEFAULT NULL TIMESTAMP(0)
enum.*?\) varchar(100)
varchar(64)(可选) VARCHAR(64 CHAR)

主键 / 外键改写

查找(正则) 替换为
PRIMARY KEY CONSTRAINT "TABLE1_PRIMARY" NOT CLUSTER PRIMARY KEY
FOREIGN KEY(.*?), FOREIGN KEY$1 WITH INDEX,
FOREIGN KEY(.*?)\n\) FOREIGN KEY$1 WITH INDEX\n)

把每个表压成一行(便于后续整表替换)

需要执行很多遍,直到没有可匹配的行——目标是把跨多行的 CREATE TABLE 折叠成一行:

查找(正则) 替换为
CREATE TABLE (.*)\n CREATE TABLE $1

再执行一遍把表末尾的右括号接上:

查找(正则) 替换为
CREATE TABLE (.*)\n\) CREATE TABLE $1 )

把占位表名 TABLE1 换回真实表名

查找(正则) 替换为
CREATE TABLE "(.*?)" (.*)TABLE1 CREATE TABLE "$1" $2$1

把索引创建从表内提取到表外

查找(正则) 替换为
, *KEY , KEY
CREATE TABLE "(.*?)" (.*?), KEY "(.*?)" (.*?),(.*) CREATE TABLE "$1" $2, $5\nCREATE OR REPLACE INDEX "$1_$3" ON "$1"$4 STORAGE(ON "MAIN", CLUSTERBTR) ;

幂等与达梦保留字处理

查找(正则) 替换为
CREATE TABLE CREATE TABLE IF NOT EXISTS
user "user"
public "public"
table(区分大小写) "table"
cluster "cluster"
resource "resource"
date "date"
skip "skip"
kubeflow.dimension (维表,转小写) kubeflow."dimension"
kubeflow.model (训练模型表,转小写) kubeflow."model"
\n\n(连续空行) \n

2.2 重建 schema 并设置当前 schema

在转换好的 SQL 顶部加上:

DROP SCHEMA "kubeflow" CASCADE;
CREATE SCHEMA "kubeflow" AUTHORIZATION "SYSDBA";
SET SCHEMA "kubeflow";

2.3 批量灌库

to_dm.py 逐行执行转换后的 kubeflow.sqldata.sql

python to_dm.py

to_dm.py 要点(见 install/kubernetes/mysql/dm/kubeflow/to_dm.py):

  • 连接串为 dm+dmPython://SYSDBA:<密码>@<host>:<port>?schema=KUBEFLOW(脚本里是写死的示例值,实际请改成你的实例);
  • dmPython.connect(... autoCommit=True) 建连接,逐行 cursor.execute(sql)
  • 单行执行失败会被 try/except 吞掉继续(容忍重复建表等报错),先执行 kubeflow.sql 再执行 data.sql

注意:to_dm.py:2 写死的示例端口是 30236,而部署小节 docker run 映射的是 30226。这两个都是示例值,实际以你映射的 NodePort 为准。

2.4 为 ab_ 开头的权限表建序列

达梦下自增主键改成了 IDENTITY 或序列。Flask-AppBuilder 的权限/用户表(ab_ 前缀)需要手工补建序列:

CREATE SEQUENCE "kubeflow"."ab_user_id_seq"            INCREMENT BY 1 MAXVALUE 9223372036854775807 MINVALUE 1;
CREATE SEQUENCE "kubeflow"."ab_role_id_seq"            INCREMENT BY 1 MAXVALUE 9223372036854775807 MINVALUE 1;
CREATE SEQUENCE "kubeflow"."ab_user_role_id_seq"       INCREMENT BY 1 MAXVALUE 9223372036854775807 MINVALUE 1;
CREATE SEQUENCE "kubeflow"."ab_permission_id_seq"      INCREMENT BY 1 MAXVALUE 9223372036854775807 MINVALUE 1;
CREATE SEQUENCE "kubeflow"."ab_view_menu_id_seq"       INCREMENT BY 1 MAXVALUE 9223372036854775807 MINVALUE 1;
CREATE SEQUENCE "kubeflow"."ab_permission_view_id_seq"      INCREMENT BY 1 MAXVALUE 9223372036854775807 MINVALUE 1;
CREATE SEQUENCE "kubeflow"."ab_permission_view_role_id_seq" INCREMENT BY 1 MAXVALUE 9223372036854775807 MINVALUE 1;

2.5 禁掉 fab 自动建权限的部分

迁移完成后,fab 创建权限的那些初始化步骤需要禁掉(否则会与已迁移的权限数据冲突)。

⚠️ 待核实:原文 to_dm.md:84 只写了「fab 创建权限的那些部分还要禁掉」,未给出具体改哪段代码。结合 install/docker/entrypoint.sh 里的 myapp fab create-adminmyapp init,禁用范围以实际代码为准,请确认。


三、连接配置回填

迁移完成后,平台通过 DM_SERVICE 连接达梦(在 docker-compose.yml 或 K8s 环境变量里设置):

# install/docker/docker-compose.yml 示例(注意去掉行首注释启用)
DM_SERVICE: 'dm+dmPython://SYSDBA:Sysdba001@192.168.3.22:5236?schema=kubeflow'

三类元数据库的优先级(MYSQL_SERVICE > POSTGRESQL_SERVICE/KINGBASE_SERVICE > DM_SERVICE)与切换细节见本段「元数据库配置.md」。

最后更新 2026-06-30完整文档以官方仓库为准:GitHub Wiki