达梦数据库 dexp/dimp 实战指南:模式克隆、REMAP_SCHEMA 与特殊字符踩坑记录
达梦数据库 dexp/dimp 实战指南:模式克隆、REMAP_SCHEMA 与特殊字符踩坑记录
2026-08-13 0 评论 2 阅读 0 点赞

达梦数据库 dexp/dimp 实战指南:模式克隆、REMAP_SCHEMA 与特殊字符踩坑记录

daimafengzi
2026-08-13 / 0 评论 / 2 阅读 / 正在检测是否收录...

达梦数据库 dexp/dimp 实战指南:模式克隆、REMAP_SCHEMA 与特殊字符踩坑记录

在日常的数据库运维和开发测试中,我们经常需要对某个模式(Schema)进行完整备份,或者将其"克隆"一份用于测试环境。在达梦数据库(DMDB)中,dexp(逻辑导出)和 dimp(逻辑导入)是完成这项工作的利器。

本文将结合实战经验,分享如何使用 dexp/dimp 进行模式导出与重命名导入(REMAP_SCHEMA),并记录一个由密码特殊字符引发的"导出 0 张表"的隐蔽 Bug。


一、核心踩坑:密码中的 .. 导致导出 0 张表

诡异的现象

在使用 dexp 导出 V5_EAM 模式时,命令行执行后瞬间结束,日志中显示:

[WARNING]invalid object:V5_EAM
export total 0 TABLE
schema[V5_EAM] export terminate.....

查询 DBA_TABLES 确认该模式下明明有 218 张表,但导出结果却是 0。

根因分析

经过排查,发现该数据库 SYSDBA 用户的密码为 woshimima..(末尾包含连续的两个点 ..)。

当在命令行直接拼接连接串时:

# 错误示范
./dexp USERID=SYSDBA/woshimima..@localhost:5236 SCHEMAS=V5_EAM ...

连续点号 .. 在 Shell 解析或 dexp 内部参数解析时,被错误地识别为路径跳转或特殊指令,导致 dexp 内部验证 Schema 属主时发生异常,从而跳过了所有对象的导出。

解决方案

方案 A(推荐):使用交互式密码输入

不在命令行中明文传递密码,执行命令后根据提示输入:

./dexp USERID=SYSDBA@localhost:5236 SCHEMAS=V5_EAM FILE=... LOG=...

方案 B:使用单引号包裹整个 USERID

利用单引号屏蔽 Shell 的特殊字符解析:

./dimp 'USERID=SYSDBA/woshimima..@localhost:5236' ...

二、实战:导出模式 (dexp)

确认连接方式后,执行完整的模式导出。建议加上 PARALLEL 参数提升导出速度。

cd /data/dmdbms/bin/

./dexp USERID=SYSDBA@localhost:5236 \
       SCHEMAS=V5_EAM \
       FILE=/data/dmexport/V5_EAM.dmp \
       LOG=/data/dmexport/V5_EAM_export.log \
       PARALLEL=4

执行后按提示输入密码。看到 terminate export success without warning 即代表完美导出。


三、实战:导入并重命名模式 (dimp + REMAP_SCHEMA)

很多时候,我们导出的数据是为了在同一实例下建立一份测试副本。这时就需要用到 REMAP_SCHEMA 参数,将源模式的数据导入到目标模式中。

⚠️ 核心注意点:目标模式必须提前创建
dimpREMAP_SCHEMA 不会自动创建目标模式!如果目标模式不存在,导入会直接报错。

Step 1:创建目标模式

/data/dmdbms/bin/disql SYSDBA@localhost:5236 -e "CREATE SCHEMA V5_EAM_TEST_0813;"

Step 2:执行导入

cd /data/dmdbms/bin/

./dimp USERID=SYSDBA@localhost:5236 \
       FILE=/data/dmexport/V5_EAM.dmp \
       LOG=/data/dmexport/V5_EAM_TEST_0813.log \
       REMAP_SCHEMA=V5_EAM:V5_EAM_TEST_0813 \
       TABLE_PARALLEL=4

参数解析:REMAP_SCHEMA=源模式:目标模式。此操作对源模式 V5_EAM 是只读的,绝对不会影响原数据。


四、总结

  • 密码安全与兼容性:强烈建议使用交互式密码输入来调用 dexp/dimp,既能避免密码泄露在 history 中,又能完美规避特殊字符(如 @..# 等)导致的解析 Bug。
  • REMAP_SCHEMA 前置条件:永远记得在导入前,先 CREATE SCHEMA 目标模式。
  • 数据完整性:导入完成后,务必通过 SELECT COUNT(*) FROM DBA_TABLES WHERE OWNER='目标模式'; 核对表数量,确保数据无损迁移。

💻 第二部分:自动化交互式 Shell 脚本

将以下代码保存为 dm_migrate.sh,赋予执行权限(chmod +x dm_migrate.sh)后运行。脚本包含了环境检查、交互式菜单、密码隐藏输入和自动创建 Schema 等完善功能。

脚本修正说明(发布前已订正):原稿在 Markdown 渲染中丢失了部分语法符号,已在此处还原/修正:

  1. 还原变量符号 ${VAR}(原稿误为 {VAR});
  2. 还原颜色转义 \033(原稿误为 033);
  3. 修正命令替换 $(...) 与退出码 $?
  4. disql 检查/建模式语句改用 双引号包裹密码user/"pass"@host:port),与文章主旨一致,规避 .. 等特殊字符被解析的坑。
#!/bin/bash

# ==============================================================================
# 达梦数据库 dexp/dimp 交互式迁移脚本
# 作者: DBA 运维助手
# 描述: 支持模式导出、模式重命名导入(REMAP_SCHEMA),自动处理前置校验
# ==============================================================================

# ================= 基础配置区 (可根据实际环境修改) =================
DM_BIN_DIR="/data/dmdbms/bin"       # 达梦 bin 目录路径
EXPORT_BASE_DIR="/data/dmexport"    # 导出文件默认存放目录
DEFAULT_HOST="localhost"            # 默认数据库 IP
DEFAULT_PORT="5236"                 # 默认数据库端口
DEFAULT_USER="SYSDBA"               # 默认执行用户
# =====================================================================

# 颜色定义
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color

# 检查达梦工具是否存在
check_env() {
    if [ ! -f "${DM_BIN_DIR}/dexp" ] || [ ! -f "${DM_BIN_DIR}/dimp" ]; then
        echo -e "${RED}[ERROR] 未找到 dexp 或 dimp 工具,请检查 DM_BIN_DIR 配置: ${DM_BIN_DIR}${NC}"
        exit 1
    fi
    mkdir -p "${EXPORT_BASE_DIR}"
}

# 获取数据库连接参数
get_db_conn() {
    read -p "请输入数据库 IP [默认 ${DEFAULT_HOST}]: " DB_HOST
    DB_HOST=${DB_HOST:-$DEFAULT_HOST}

    read -p "请输入数据库端口 [默认 ${DEFAULT_PORT}]: " DB_PORT
    DB_PORT=${DB_PORT:-$DEFAULT_PORT}

    read -p "请输入数据库用户名 [默认 ${DEFAULT_USER}]: " DB_USER
    DB_USER=${DB_USER:-$DEFAULT_USER}

    echo -n "请输入 ${DB_USER} 的密码 (输入时不可见): "
    read -s DB_PASS
    echo ""

    if [ -z "${DB_PASS}" ]; then
        echo -e "${RED}[ERROR] 密码不能为空!${NC}"
        exit 1
    fi

    # dexp/dimp:用单引号包裹整个 USERID,防止密码中的特殊字符(如 .. @ #)被 Shell 解析
    CONN_STR="'USERID=${DB_USER}/${DB_PASS}@${DB_HOST}:${DB_PORT}'"
    # disql:用双引号包裹密码(达梦语法 user/"pass"@host:port),同样规避特殊字符
    DISQL_CONN="${DB_USER}/\"${DB_PASS}\"@${DB_HOST}:${DB_PORT}"
}

# 导出模式
do_export() {
    echo -e "\n${BLUE}========== 模式导出 (dexp) ==========${NC}"
    get_db_conn

    read -p "请输入要导出的源模式名 (如 V5_EAM): " SRC_SCHEMA
    if [ -z "${SRC_SCHEMA}" ]; then
        echo -e "${RED}[ERROR] 模式名不能为空!${NC}"
        return
    fi

    TIMESTAMP=$(date +%Y%m%d_%H%M%S)
    DMP_FILE="${EXPORT_BASE_DIR}/${SRC_SCHEMA}_${TIMESTAMP}.dmp"
    LOG_FILE="${EXPORT_BASE_DIR}/${SRC_SCHEMA}_${TIMESTAMP}_exp.log"

    echo -e "${YELLOW}[INFO] 开始导出 ${SRC_SCHEMA} 到 ${DMP_FILE} ...${NC}"

    # 使用 eval 执行带有单引号的连接串(去掉外层单引号后整体作为一个参数传给 dexp)
    eval "${DM_BIN_DIR}/dexp ${CONN_STR} SCHEMAS=${SRC_SCHEMA} FILE=${DMP_FILE} LOG=${LOG_FILE} PARALLEL=4"

    if [ $? -eq 0 ]; then
        echo -e "${GREEN}[SUCCESS] 导出完成!请检查日志: ${LOG_FILE}${NC}"
    else
        echo -e "${RED}[ERROR] 导出失败,请查看日志排查原因: ${LOG_FILE}${NC}"
    fi
}

# 导入模式
do_import() {
    echo -e "\n${BLUE}========== 模式导入 (dimp + REMAP) ==========${NC}"
    get_db_conn

    read -p "请输入 DMP 文件绝对路径: " DMP_FILE
    if [ ! -f "${DMP_FILE}" ]; then
        echo -e "${RED}[ERROR] 文件不存在: ${DMP_FILE}${NC}"
        return
    fi

    read -p "请输入 DMP 文件中的源模式名 (如 V5_EAM): " SRC_SCHEMA
    read -p "请输入要导入的目标模式名 (如 V5_EAM_TEST_0813): " DEST_SCHEMA

    if [ -z "${SRC_SCHEMA}" ] || [ -z "${DEST_SCHEMA}" ]; then
        echo -e "${RED}[ERROR] 模式名不能为空!${NC}"
        return
    fi

    # 检查目标模式是否存在,不存在则提示创建
    echo -e "${YELLOW}[INFO] 检查目标模式 ${DEST_SCHEMA} 是否存在...${NC}"
    CHECK_SQL="SELECT COUNT(*) FROM DBA_USERS WHERE USERNAME='${DEST_SCHEMA}';"
    # 使用 disql 检查(密码用双引号包裹,规避特殊字符)
    USER_EXISTS=$(echo "${CHECK_SQL}" | ${DM_BIN_DIR}/disql ${DISQL_CONN} -e 2>/dev/null | grep -oE '[0-9]+' | head -1)

    if [ "${USER_EXISTS}" != "1" ]; then
        echo -e "${YELLOW}[WARNING] 目标模式 ${DEST_SCHEMA} 不存在!dimp 不会自动创建模式。${NC}"
        read -p "是否立即通过 SYSDBA 创建该模式? (y/n): " CREATE_CHOICE
        if [[ "${CREATE_CHOICE}" =~ ^[Yy] ]]; then
            ${DM_BIN_DIR}/disql ${DISQL_CONN} -e "CREATE SCHEMA ${DEST_SCHEMA};"
            if [ $? -eq 0 ]; then
                echo -e "${GREEN}[SUCCESS] 模式 ${DEST_SCHEMA} 创建成功!${NC}"
            else
                echo -e "${RED}[ERROR] 模式创建失败,请检查权限或名称是否合法。${NC}"
                return
            fi
        else
            echo -e "${RED}[INFO] 取消导入。请先手动创建目标模式。${NC}"
            return
        fi
    fi

    TIMESTAMP=$(date +%Y%m%d_%H%M%S)
    LOG_FILE="${EXPORT_BASE_DIR}/${DEST_SCHEMA}_${TIMESTAMP}_imp.log"

    echo -e "${YELLOW}[INFO] 开始导入 ${SRC_SCHEMA} -> ${DEST_SCHEMA} ...${NC}"

    eval "${DM_BIN_DIR}/dimp ${CONN_STR} FILE=${DMP_FILE} LOG=${LOG_FILE} REMAP_SCHEMA=${SRC_SCHEMA}:${DEST_SCHEMA} TABLE_PARALLEL=4"

    if [ $? -eq 0 ]; then
        echo -e "${GREEN}[SUCCESS] 导入完成!请检查日志: ${LOG_FILE}${NC}"
    else
        echo -e "${RED}[ERROR] 导入出现异常,请查看日志排查原因: ${LOG_FILE}${NC}"
    fi
}

# 主菜单
main_menu() {
    check_env
    while true; do
        echo -e "\n${GREEN}========================================${NC}"
        echo -e "${GREEN}   达梦数据库 dexp/dimp 迁移工具箱${NC}"
        echo -e "${GREEN}========================================${NC}"
        echo "1. 导出模式 (Export Schema)"
        echo "2. 导入模式 (Import & REMAP_SCHEMA)"
        echo "0. 退出"
        echo -e "${GREEN}----------------------------------------${NC}"
        read -p "请选择操作 [0-2]: " CHOICE

        case ${CHOICE} in
            1) do_export ;;
            2) do_import ;;
            0) echo -e "${BLUE}再见!${NC}"; exit 0 ;;
            *) echo -e "${RED}[ERROR] 无效的选择,请重新输入。${NC}" ;;
        esac
    done
}

# 执行主菜单
main_menu

💡 脚本使用指南

  1. 创建脚本文件:vi /data/dm_migrate.sh
  2. 粘贴上述代码并保存。
  3. 赋予执行权限:chmod +x /data/dm_migrate.sh
  4. 运行脚本:./dm_migrate.sh

脚本亮点

  • 隐藏密码输入:使用 read -s,密码不会在屏幕上显示,也不会留在命令历史中。
  • 自动处理特殊字符:脚本内部自动对 dexp/dimp 用单引号包裹连接串('USERID=...')、对 disql 用双引号包裹密码(user/"pass"@host:port),完美解决你之前遇到的 .. 密码解析 Bug。
  • 智能校验:在选择导入时,脚本会自动调用 disql 检查目标模式是否存在。如果不存在,会主动询问并帮你创建,避免了 dimp 因找不到目标 Schema 而报错的问题。
  • 自动命名:导出文件和日志自动加上 年月日_时分秒 时间戳,防止覆盖历史备份。
0

评论 (0)

取消