跳过正文

达梦通过 DBLINK 连接 Oracle、MySQL、PostgreSQL 实战:国产化迁移后的快速数据核对

Greatfinish
作者
Greatfinish
记录 Oracle、PostgreSQL、达梦、Linux、存储与生产环境故障处理经验。
目录

实验日期:2026-08-03
适用场景:业务已经迁移到达梦,仍需直接读取 Oracle、MySQL 或 PostgreSQL 源表,核对行数、金额、主键和明细差异。
安全说明:文中的密码统一写成 <DBLINK_PASSWORD>。源库应使用只读专用账号,服务器 root 密码不得写入脚本、文章或 odbc.ini

迁移后的比对 SQL 往往不复杂,取数却很耗时间。每轮核对都要导出、传输和装载源端数据,反馈自然会变慢。DM 的外部链接对象 LINK 可以通过 远程表@LINK名 直接访问源表,适合在割接前后执行聚合、抽查和差集核对。

CREATE LINK 要放在链路检查的最后。查询能否稳定执行,取决于操作系统、客户端或 ODBC 驱动、源库版本和 DM 补丁版是否兼容。三类数据库的实际数据流如下:

Oracle:      DM SQL -> LINK -> OCI/libclntsh -> Oracle
MySQL/PG:    DM SQL -> LINK -> unixODBC -> DSN -> ODBC 驱动 -> 源库

Oracle 要先验证动态库和服务名;MySQL、PostgreSQL 要先验证 DSN,再从 DM 会话查询远程表。isql 成功只能说明 ODBC 驱动能够通过 DSN 访问源库。DM 是否支持驱动返回的数据类型元数据,还要用 LINK 查询确认。本次测试 MySQL 8.0.29 驱动时,isql 查询成功,DM LINK 随后报 [-2246]

DBLINK 适合以下短期任务:

  • 比较源端和 DM 端的行数、业务汇总值与最大更新时间;
  • 按主键抽查迁移前后的字段值;
  • 用双向 MINUS 查找缺失行和内容不一致的行;
  • 在割接观察期确认源端是否仍有增量数据。

它不适合代替同步平台,也不适合承担高频远程写入。异构链路还会受到字符集转换、网络抖动和查询下推差异的影响,大表核对应按主键或业务日期分批执行。

实测环境与结果
#

四台测试主机与软件版本
#

角色地址操作系统数据库/组件字符集或关键说明
DM 端192.168.17.37CentOS 7 x86_64,glibc 2.17DM8,ID_CODE=03134284336-20250117-257733-20132UTF-8,端口 5236
Oracle 源端192.168.17.11Oracle Linux 7.9 x86_64Oracle 11.2.0.4,服务名 orclZHS16GBK,端口 1521
MySQL 源端192.168.17.57CentOS 7 x86_64MySQL 5.7.29实验库 dblink_lab 使用 utf8mb4,端口 3306
PostgreSQL 源端192.168.17.16Rocky Linux 9.3 x86_64PostgreSQL 16.3UTF8,端口 5432

DM 端实际安装的客户端组件如下:

组件实测版本安装目录
Oracle Instant Client19.31/opt/oracle/instantclient_19_31
unixODBC2.3.9/usr/local/unixODBC-2.3.9
MySQL Connector/ODBC5.3.14,glibc 2.12 通用包/opt/dblink-lab/mysql-connector-odbc-5.3.14-linux-glibc2.12-x86-64bit
PostgreSQL 客户端库16.3/usr/local/postgresql-16.3
psqlODBC16.00.0000/usr/local/psqlodbc-16.00.0000

三条 LINK 的验证结果#

LINK源表行数金额合计中文字段聚合核对
ORA_LINK3601.50正常PASS
MYSQL_LINK3661.50正常PASS
PG_LINK3721.50正常PASS

三条 LINK 均从 DM 会话读取成功。MySQL 测试表随后执行双向 MINUS,明细差异行数为 0。验证内容包括连接、对象访问、数值聚合和中文转换。

介质下载与校验
#

官方下载入口:

下表记录本次实验实际使用的介质。部署前核对 SHA-256,可以排除下载不完整或文件被替换的问题。

文件SHA-256
instantclient-basic-linux.x64-19.31.0.0.0dbru.zipa4433867b83d170d093198651ecd6f74db1030168835b96e88bd605e4c900de3
mysql-connector-odbc-5.3.14-linux-glibc2.12-x86-64bit.tar.gze7ca39163810b39e2e5925a7c877187536a8ed4f129dc2c39d073351b116a446
postgresql-16.3.tar.gzbd3798c399bc1b6d08b94340f9dd7a75a30a7fa076788ef2f4848be2be6a5fc5
psqlodbc-16.00.0000.tar.gzafd892f89d2ecee8d3f3b2314f1bd5bf2d02201872c6e3431e5c31096eca4c8b
unixODBC-2.3.9.tar.gz52833eac3d681c8b0c9a5a65f2ebd745b3a964f208fc748f977e44015a31b207

下载示例:

mkdir -p /opt/dblink-lab/media
cd /opt/dblink-lab/media

curl -LO https://download.oracle.com/otn_software/linux/instantclient/1931000v2/instantclient-basic-linux.x64-19.31.0.0.0dbru.zip
curl -LO https://dev.mysql.com/get/Downloads/Connector-ODBC/5.3/mysql-connector-odbc-5.3.14-linux-glibc2.12-x86-64bit.tar.gz
curl -LO https://ftp.postgresql.org/pub/source/v16.3/postgresql-16.3.tar.gz
curl -LO https://ftp.postgresql.org/pub/odbc/versions.old/src/psqlodbc-16.00.0000.tar.gz
curl -LO https://www.unixodbc.org/unixODBC-2.3.9.tar.gz

sha256sum *

如果数据库服务器不能访问互联网,可在运维机下载并校验后,通过受控文件传输工具上传。不要临时关闭系统证书校验。

第一部分:DM-Oracle 之 DBLINK#

1.1 组件与兼容性说明
#

Oracle LINK 走 OCI,不经过 unixODBC。DM 进程必须能够加载 Oracle 客户端的 libclntsh.so,客户端还要与 DM 主机的 CPU 架构和 glibc 兼容。本次 DM 服务器使用 glibc 2.17,因此选择 Oracle Instant Client 19.31;Oracle 官方说明 OCI 19.3 可连接 Oracle 11.2 及以上版本。

本次实验还覆盖了跨字符集查询:DM 为 UTF-8,Oracle 为 ZHS16GBK。当前 DM 版本能正确完成中文转换;老版本若出现 ORA-0140: fetched column value was truncated,应优先升级 DM,不要长期依赖放大列长度的绕过参数。

1.2 Oracle 源端准备
#

先确认监听、服务名、版本和字符集。这四项分别决定网络入口、连接描述符、客户端兼容范围和字符转换路径。

su - oracle
lsnrctl status
sqlplus / as sysdba
select banner from v$version;
select name, open_mode from v$database;
select value from v$parameter where name='service_names';
select value
  from nls_database_parameters
 where parameter='NLS_CHARACTERSET';

创建专用只读账号。实验为了建表先授予建表权限;正式迁移核对只需要 CREATE SESSION 和目标表的 SELECT

create user DM_DBLINK identified by "<DBLINK_PASSWORD>"
  default tablespace USERS
  temporary tablespace TEMP
  quota unlimited on USERS;

grant create session, create table to DM_DBLINK;

准备测试表:

create table DM_DBLINK.MIGRATION_CHECK (
  ID          number(10) primary key,
  BIZ_CODE    varchar2(30) not null,
  AMOUNT      number(12,2),
  NOTE        varchar2(100),
  UPDATE_TIME date
);

insert into DM_DBLINK.MIGRATION_CHECK values
  (1,'ORA-001',100.25,'迁移前订单',to_date('2026-08-03 10:01:02','yyyy-mm-dd hh24:mi:ss'));
insert into DM_DBLINK.MIGRATION_CHECK values
  (2,'ORA-002',200.50,'待核对退款',to_date('2026-08-03 10:02:03','yyyy-mm-dd hh24:mi:ss'));
insert into DM_DBLINK.MIGRATION_CHECK values
  (3,'ORA-003',300.75,'核对通过',to_date('2026-08-03 10:03:04','yyyy-mm-dd hh24:mi:ss'));
commit;

select count(*), sum(amount) from DM_DBLINK.MIGRATION_CHECK;

生产账号建议改为:

revoke create table from DM_DBLINK;
grant select on 业务模式.待核对表 to DM_DBLINK;

1.3 DM 端安装 Oracle Instant Client
#

yum install -y libaio unzip

mkdir -p /opt/oracle
unzip /opt/dblink-lab/media/instantclient-basic-linux.x64-19.31.0.0.0dbru.zip \
  -d /opt/oracle

echo '/opt/oracle/instantclient_19_31' \
  > /etc/ld.so.conf.d/oracle-instantclient.conf
ldconfig

ldd /opt/oracle/instantclient_19_31/libclntsh.so.19.1

ldd 会列出 libclntsh.so 的运行时依赖。输出中出现 not found 时,DM 进程也无法加载 OCI;应先通过系统软件源补齐匹配的兼容包。CentOS 7 通常已经包含 libnsl.so.1

dmdba 配置环境变量:

cat >> /home/dmdba/.bash_profile <<'EOF'
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/opt/oracle/instantclient_19_31
EOF

chown dmdba:dinstall /home/dmdba/.bash_profile
su - dmdba -c 'source ~/.bash_profile; echo $LD_LIBRARY_PATH'

.bash_profile 只在对应用户登录时生效,已经运行的 DM 服务未必继承其中的变量。把客户端目录写入 ld.so.conf.d 并执行 ldconfig,可以让系统动态加载器识别该目录。集群环境要在每个可能运行 DM 实例的节点安装相同客户端。

1.4 从 DM 到 Oracle 的网络检查
#

timeout 3 bash -c '</dev/tcp/192.168.17.11/1521' \
  && echo reachable \
  || echo unreachable

如果端口不通,先处理路由、防火墙和监听,不要反复修改 LINK 语法。

1.5 创建与验证 Oracle LINK#

网络、动态库、账号和服务名都通过检查后,再创建 LINK。最简连接串采用 IP:端口/服务名

create or replace public link "ORA_LINK"
  connect 'ORACLE'
  with "DM_DBLINK"
  identified by "<DBLINK_PASSWORD>"
  using '192.168.17.11:1521/orcl';

也可以使用完整连接描述符:

create or replace public link "ORA_LINK"
  connect 'ORACLE'
  with "DM_DBLINK"
  identified by "<DBLINK_PASSWORD>"
  using '(DESCRIPTION=
           (ADDRESS=(PROTOCOL=TCP)(HOST=192.168.17.11)(PORT=1521))
           (CONNECT_DATA=(SERVICE_NAME=orcl)))';

查询验证:

select count(*) as rows_count,
       sum("AMOUNT") as amount_sum
  from "DM_DBLINK"."MIGRATION_CHECK"@"ORA_LINK";

select "ID","BIZ_CODE","AMOUNT","NOTE","UPDATE_TIME"
  from "DM_DBLINK"."MIGRATION_CHECK"@"ORA_LINK"
 order by "ID";

实测返回 3 行、金额合计 601.50,GBK 源库中的中文在 UTF-8 DM 端显示正常。

[dmdba@dameng-srv ~]$ disql SYSDBA
password:

Server[LOCALHOST:5236]:mode is normal, state is open
login used time : 3.628(ms)
disql V8
SQL> select count(*) as rows_count,
       sum("AMOUNT") as amount_sum
  from "DM_DBLINK"."MIGRATION_CHECK"@"ORA_LINK";2   3   

LINEID     rows_count           amount_sum
---------- -------------------- ----------
1          3                    601.5

used time: 6.323(ms). Execute id is 5065101.
SQL> select "ID","BIZ_CODE","AMOUNT","NOTE","UPDATE_TIME"
  from "DM_DBLINK"."MIGRATION_CHECK"@"ORA_LINK"
 order by "ID";2   3   

LINEID     ID BIZ_CODE AMOUNT NOTE            UPDATE_TIME        
---------- -- -------- ------ --------------- -------------------
1          1  ORA-001  100.25 迁移前订单 2026-08-03 10:01:02
2          2  ORA-002  200.5  待核对退款 2026-08-03 10:02:03
3          3  ORA-003  300.75 核对通过    2026-08-03 10:03:04

used time: 4.734(ms). Execute id is 5065102.
SQL> 

1.6 Oracle 常见故障
#

[-6033]: DBLINK 连接丢失#

依次检查:

  1. DM 到 Oracle 的 1521 端口;
  2. 用户名和密码,尤其是加引号后大小写敏感的账号;
  3. lsnrctl status 中的服务名,而不是只看实例名;
  4. DM 实例日志中的 Oracle 原始错误码。

ORA-21561: OID generation failed
#

检查 DM 主机名能否在 /etc/hosts 正确解析。

DBLINK 加载库文件失败#

su - dmdba -c 'env | grep LD_LIBRARY_PATH'
ldd /opt/oracle/instantclient_19_31/libclntsh.so.19.1
ls -ld /opt/oracle/instantclient_19_31

同时确认客户端 CPU 架构与 DM 主机一致,且 dmdba 对目录和文件有读取权限。

跨字符集“字符串截断”
#

优先升级到支持自动放大与字符集转换的新 DM 版本。option(bytes_in_char=3) 只适合作为经过验证的临时绕过方式,遇到固定长度 CHAR 或过程参数时要额外测试。

1.7 Oracle LINK 验证结果#

OCI 动态库、Oracle 服务名、跨字符集查询和 DM 远程对象访问均通过验证。查询返回 3 行、金额合计 601.50,中文显示正常。LINK 连接失败时,可依次检查端口、服务名、动态库和源端原始错误码,不必反复改写 CREATE LINK

第二部分:DM-MySQL 之 DBLINK#

2.1 组件与版本选择
#

MySQL LINK 通过 ODBC 建立。四个组件各自负责一层:

  • unixODBC 负责加载驱动,并提供 DSN 管理和 isql 测试工具;
  • MySQL Connector/ODBC 负责与 MySQL 服务端通信;
  • /etc/odbcinst.ini 记录驱动名称和共享库路径;
  • /etc/odbc.ini 把主机、端口、数据库和账号组织成 DSN。

附件手册使用 MySQL 8.0.41 和 Connector/ODBC 8.0.33(glibc 2.28),本次 DM 主机则是 CentOS 7/glibc 2.17,源端为 MySQL 5.7.29。glibc 2.28 的二进制包无法在 glibc 2.17 上直接加载,驱动版本不能照搬。

实验先测试了 Connector/ODBC 8.0.29(glibc 2.12)。isql 可以查询,DM LINK 却返回 [-2246]: DBLINK not support for the data type。改用与 MySQL 5.7 同代的 Connector/ODBC 5.3.14 后,两项测试均通过。这说明驱动可加载且能访问 MySQL 时,DM 仍可能无法处理驱动上报的某些类型元数据。本文记录的是本次实验可用的组合,其他 DM 补丁版应按厂商兼容矩阵和实际字段回归结果选择驱动。

2.2 MySQL 源端准备
#

确认版本、监听和字符集:

select @@version,
       @@port,
       @@character_set_server,
       @@collation_server;

创建实验库、专用只读账号和测试表。只允许 DM 主机地址登录:

create database if not exists dblink_lab
  default character set utf8mb4
  collate utf8mb4_unicode_ci;

create user 'dm_dblink'@'192.168.17.37'
  identified by '<DBLINK_PASSWORD>';

grant select on dblink_lab.*
  to 'dm_dblink'@'192.168.17.37';
flush privileges;

create table dblink_lab.migration_check (
  id          int primary key,
  biz_code    varchar(30) not null,
  amount      decimal(12,2),
  note        varchar(100),
  update_time datetime
) engine=InnoDB default charset=utf8mb4;

insert into dblink_lab.migration_check values
  (1,'MYSQL-001',110.25,'迁移前订单','2026-08-03 11:01:02'),
  (2,'MYSQL-002',220.50,'待核对退款','2026-08-03 11:02:03'),
  (3,'MYSQL-003',330.75,'核对通过','2026-08-03 11:03:04');

select count(*), sum(amount)
  from dblink_lab.migration_check;

2.3 DM 端安装 unixODBC 2.3.9
#

如果在第一条 ODBC LINK 前尚未安装 unixODBC,执行:

yum install -y gcc gcc-c++ make

mkdir -p /opt/dblink-lab/src
tar -xzf /opt/dblink-lab/media/unixODBC-2.3.9.tar.gz \
  -C /opt/dblink-lab/src

cd /opt/dblink-lab/src/unixODBC-2.3.9
./configure \
  --prefix=/usr/local/unixODBC-2.3.9 \
  --sysconfdir=/etc
make -j"$(nproc)"
make install

/usr/local/unixODBC-2.3.9/bin/isql --version
/usr/local/unixODBC-2.3.9/bin/odbcinst -j

--sysconfdir=/etc 把 unixODBC 的系统配置目录固定为 /etc,后续的 /etc/odbcinst.ini/etc/odbc.ini 才会被同一套工具读取。若安装时使用其他目录,应以 odbcinst -j 的输出为准。

2.4 安装并注册 MySQL ODBC 驱动
#

cd /opt/dblink-lab
tar -xzf media/mysql-connector-odbc-5.3.14-linux-glibc2.12-x86-64bit.tar.gz

MYSQL_ODBC_HOME=/opt/dblink-lab/mysql-connector-odbc-5.3.14-linux-glibc2.12-x86-64bit
ldd "$MYSQL_ODBC_HOME/lib/libmyodbc5a.so"

/etc/odbcinst.ini 注册 ANSI 驱动:

[MySQL ODBC 5.3 ANSI Driver]
Description=MySQL Connector/ODBC 5.3.14 ANSI
Driver=/opt/dblink-lab/mysql-connector-odbc-5.3.14-linux-glibc2.12-x86-64bit/lib/libmyodbc5a.so
Setup=/opt/dblink-lab/mysql-connector-odbc-5.3.14-linux-glibc2.12-x86-64bit/lib/libmyodbc5a.so
FileUsage=1

检查注册结果:

/usr/local/unixODBC-2.3.9/bin/odbcinst -q -d

2.5 配置 MySQL DSN
#

编辑 /etc/odbc.ini

[MYSQL_DBLINK]
Description=DM to MySQL 5.7
Driver=MySQL ODBC 5.3 ANSI Driver
Server=192.168.17.57
Database=dblink_lab
User=dm_dblink
Password=<DBLINK_PASSWORD>
Port=3306
Charset=utf8mb4

保护明文密码:

chown root:dinstall /etc/odbc.ini
chmod 0640 /etc/odbc.ini
chmod 0644 /etc/odbcinst.ini

注意事项:

  • INI 配置项行首不要有多余空格;
  • 不要把说明文字写在配置值后面;
  • Driver 必须与 odbcinst.ini 中的节名完全一致;
  • 生产密码应由密码管理系统生成并定期轮换。

2.6 配置环境变量并验证 ODBC
#

cat >> /home/dmdba/.bash_profile <<'EOF'
export UNIXODBC_HOME=/usr/local/unixODBC-2.3.9
export ODBCSYSINI=/etc
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$UNIXODBC_HOME/lib
EOF

chown dmdba:dinstall /home/dmdba/.bash_profile

在 root 和 dmdba 下分别验证,重点是 dmdba:

/usr/local/unixODBC-2.3.9/bin/isql \
  -v MYSQL_DBLINK dm_dblink '<DBLINK_PASSWORD>'

su - dmdba -c "/usr/local/unixODBC-2.3.9/bin/isql \
  -v MYSQL_DBLINK dm_dblink '<DBLINK_PASSWORD>'"

进入 SQL> 后执行:

select count(*) as rows_count,
       sum(amount) as amount_sum
  from migration_check;

isql 成功后仍要继续执行 DM 远程表查询。本实验中的 8.0.29 驱动就在这两步之间暴露出兼容问题。

2.7 创建与验证 MySQL LINK#

create or replace public link "MYSQL_LINK"
  connect 'ODBC'
  with "dm_dblink"
  identified by "<DBLINK_PASSWORD>"
  using 'MYSQL_DBLINK';

using 后面的 MYSQL_DBLINK/etc/odbc.ini 中的 DSN 名,不是数据库名。

验证:

select count(*) as rows_count,
       sum("amount") as amount_sum
  from "migration_check"@"MYSQL_LINK";

select "id","biz_code","amount","note","update_time"
  from "migration_check"@"MYSQL_LINK"
 order by "id";

实测返回 3 行、金额合计 661.50,中文和 datetime 均正确。

[dmdba@dameng-srv ~]$ disql SYSDBA
password:

Server[LOCALHOST:5236]:mode is normal, state is open
login used time : 3.587(ms)
disql V8
SQL> select count(*) as rows_count,
       sum("amount") as amount_sum
  from "migration_check"@"MYSQL_LINK";2   3   

LINEID     rows_count           amount_sum
---------- -------------------- ----------
1          3                    661.5

used time: 14.453(ms). Execute id is 5066001.
SQL> select "id","biz_code","amount","note","update_time"
  from "migration_check"@"MYSQL_LINK"
 order by "id";2   3   

LINEID     id          biz_code  amount note            update_time        
---------- ----------- --------- ------ --------------- -------------------
1          1           MYSQL-001 110.25 迁移前订单 2026-08-03 11:01:02
2          2           MYSQL-002 220.5  待核对退款 2026-08-03 11:02:03
3          3           MYSQL-003 330.75 核对通过    2026-08-03 11:03:04

used time: 7.903(ms). Execute id is 5066002.
SQL> 

2.8 MySQL 常见故障
#

驱动无法加载或 GLIBC_x.xx not found
#

getconf GNU_LIBC_VERSION
ldd /实际路径/libmyodbc*.so

下载驱动前必须先核对 glibc。CentOS 7/glibc 2.17 不能使用 glibc 2.28 构建的通用包。

isql 成功,但 DM 报 [-2246]
#

这通常是 DM 补丁版、MySQL 版本与 ODBC 驱动返回的数据类型元数据不匹配。本次的处理路径是:

  1. 逐列查询确认不是单个业务字段导致;
  2. 用 ANSI/Unicode 两种 8.0.29 驱动复测;
  3. 结合 MySQL 5.7 版本切换到 Connector/ODBC 5.3.14;
  4. 重新执行 isql 和 DM LINK 查询,两层均通过。

生产环境不要盲目降级驱动,应先查 DM 补丁说明和认证矩阵,并在测试环境覆盖实际数据类型。

ODBC 配置找不到
#

/usr/local/unixODBC-2.3.9/bin/odbcinst -j

确认 SYSTEM DATA SOURCES 与实际 odbc.ini 路径一致。必要时设置 ODBCSYSINI=/etc

2.9 MySQL LINK 验证结果#

lddisql 和 DM 远程表查询均通过。Connector/ODBC 5.3.14 组合返回 3 行、金额合计 661.50,中文和 datetime 正常。驱动升级或 DM 打补丁后,应重新执行这三项检查,原有的 isql 结果不能代替 LINK 回归。

第三部分:DM-PostgreSQL 之 DBLINK#

3.1 组件说明
#

PostgreSQL LINK 同样经过 unixODBC,但驱动换成 psqlODBC。psqlODBC 编译时读取 PostgreSQL 客户端头文件,运行时加载 libpq.so,两者必须来自兼容版本。

第一次编译直接使用 CentOS 7 自带的 PostgreSQL 9.2 开发包。psqlODBC 16.00.0000 需要的 PG_DIAG_SCHEMA_NAMEPG_DIAG_TABLE_NAME 等定义不存在,编译因此失败。安装 PostgreSQL 16.3 客户端库,并通过 --with-libpq=/usr/local/postgresql-16.3 显式指定头文件和库后,编译通过。

附件手册在 DM 端完整部署 PostgreSQL,是为了获得匹配的 libpq。如果 DM 主机只承担 DBLINK 查询,可以只安装客户端库。本文从源码执行标准 make install,没有执行 initdb,也没有启动本地 PostgreSQL 服务。

3.2 PostgreSQL 源端准备
#

确认版本与监听:

select version();
show port;
show listen_addresses;
select pg_encoding_to_char(encoding)
  from pg_database
 where datname=current_database();

创建专用账号、实验库和测试表:

create role dm_dblink
  login
  password '<DBLINK_PASSWORD>';
createdb -O dm_dblink -E UTF8 dblink_lab
psql -d dblink_lab
create table public.migration_check (
  id          integer primary key,
  biz_code    varchar(30) not null,
  amount      numeric(12,2),
  note        varchar(100),
  update_time timestamp without time zone
);

alter table public.migration_check owner to dm_dblink;

insert into public.migration_check values
  (1,'PG-001',120.25,'迁移前订单','2026-08-03 12:01:02'),
  (2,'PG-002',240.50,'待核对退款','2026-08-03 12:02:03'),
  (3,'PG-003',360.75,'核对通过','2026-08-03 12:03:04');

postgresql.conf 中监听业务地址:

listen_addresses = '*'

pg_hba.conf 中只允许 DM 主机访问专用数据库和账号:

host  dblink_lab  dm_dblink  192.168.17.37/32  scram-sha-256

重载配置:

select pg_reload_conf();

实验环境原有 0.0.0.0/0 trust 规则虽然能连接,但不应照搬到生产。至少应限制源 IP,并使用密码认证。

3.3 安装 unixODBC
#

如果 MySQL 部分已经完成,可直接复用 /usr/local/unixODBC-2.3.9。全新环境的编译命令与第二部分相同:

tar -xzf /opt/dblink-lab/media/unixODBC-2.3.9.tar.gz \
  -C /opt/dblink-lab/src
cd /opt/dblink-lab/src/unixODBC-2.3.9
./configure --prefix=/usr/local/unixODBC-2.3.9 --sysconfdir=/etc
make -j"$(nproc)"
make install

3.4 安装 PostgreSQL 16.3 客户端库
#

准备编译环境:

yum install -y gcc gcc-c++ make openssl-devel

编译到独立目录,避免覆盖系统自带 PostgreSQL:

tar -xzf /opt/dblink-lab/media/postgresql-16.3.tar.gz \
  -C /opt/dblink-lab/src

cd /opt/dblink-lab/src/postgresql-16.3
./configure \
  --prefix=/usr/local/postgresql-16.3 \
  --without-readline \
  --without-zlib \
  --without-icu \
  --with-openssl

make -j"$(nproc)"
make install

/usr/local/postgresql-16.3/bin/pg_config --version

把客户端库加入动态加载路径:

echo '/usr/local/postgresql-16.3/lib' \
  > /etc/ld.so.conf.d/postgresql16-client.conf
ldconfig

3.5 编译安装 psqlODBC 16.00.0000
#

tar -xzf /opt/dblink-lab/media/psqlodbc-16.00.0000.tar.gz \
  -C /opt/dblink-lab/src

cd /opt/dblink-lab/src/psqlodbc-16.00.0000
./configure \
  --prefix=/usr/local/psqlodbc-16.00.0000 \
  --with-unixodbc=/usr/local/unixODBC-2.3.9 \
  --with-libpq=/usr/local/postgresql-16.3

make -j"$(nproc)"
make install

ldd /usr/local/psqlodbc-16.00.0000/lib/psqlodbcw.so

这里的 ldd 同时验证 psqlODBC 的直接依赖和最终加载的 libpq。输出应显示 libpq.so.5 指向 /usr/local/postgresql-16.3/lib/libpq.so.5,且没有 not found

3.6 注册 PostgreSQL ODBC 驱动
#

/etc/odbcinst.ini 增加:

[PostgreSQL Unicode]
Description=PostgreSQL ODBC 16.00 Unicode
Driver=/usr/local/psqlodbc-16.00.0000/lib/psqlodbcw.so
Setup=/usr/local/psqlodbc-16.00.0000/lib/psqlodbcw.so
FileUsage=1

/etc/odbc.ini 增加:

[PG_DBLINK]
Description=DM to PostgreSQL 16
Driver=PostgreSQL Unicode
Servername=192.168.17.16
Database=dblink_lab
Username=dm_dblink
Password=<DBLINK_PASSWORD>
Port=5432
ReadOnly=1

继续保持配置文件最小权限:

chown root:dinstall /etc/odbc.ini
chmod 0640 /etc/odbc.ini

3.7 环境变量与 ODBC 验证
#

cat >> /home/dmdba/.bash_profile <<'EOF'
export UNIXODBC_HOME=/usr/local/unixODBC-2.3.9
export ODBCSYSINI=/etc
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/local/unixODBC-2.3.9/lib:/usr/local/psqlodbc-16.00.0000/lib:/usr/local/postgresql-16.3/lib
EOF

测试:

su - dmdba -c "/usr/local/unixODBC-2.3.9/bin/isql \
  -v PG_DBLINK dm_dblink '<DBLINK_PASSWORD>'"
select count(*) as rows_count,
       sum(amount) as amount_sum
  from public.migration_check;

实测 isql 返回 3 行、金额合计 721.50,中文与时间戳正常。

3.8 创建与验证 PostgreSQL LINK#

create or replace public link "PG_LINK"
  connect 'ODBC'
  with "dm_dblink"
  identified by "<DBLINK_PASSWORD>"
  using 'PG_DBLINK';

查询时保留 PostgreSQL 的小写对象名,并用双引号:

select count(*) as rows_count,
       sum("amount") as amount_sum
  from "public"."migration_check"@"PG_LINK";

select "id","biz_code","amount","note","update_time"
  from "public"."migration_check"@"PG_LINK"
 order by "id";

实测返回 3 行、金额合计 721.50。

[dmdba@dameng-srv ~]$ disql SYSDBA
password:

Server[LOCALHOST:5236]:mode is normal, state is open
login used time : 3.770(ms)
disql V8
SQL> select count(*) as rows_count,
       sum("amount") as amount_sum
  from "public"."migration_check"@"PG_LINK";2   3   

LINEID     rows_count           amount_sum
---------- -------------------- ----------
1          3                    721.5

used time: 6.743(ms). Execute id is 5067301.
SQL> select "id","biz_code","amount","note","update_time"
  from "public"."migration_check"@"PG_LINK"
 order by "id";2   3   

LINEID     id          biz_code amount note            update_time               
---------- ----------- -------- ------ --------------- --------------------------
1          1           PG-001   120.25 迁移前订单 2026-08-03 12:01:02.000000
2          2           PG-002   240.5  待核对退款 2026-08-03 12:02:03.000000
3          3           PG-003   360.75 核对通过    2026-08-03 12:03:04.000000

used time: 5.868(ms). Execute id is 5067302.
SQL> 

3.9 PostgreSQL 常见故障
#

isql 连接被拒绝
#

检查:

show listen_addresses;
show port;
select * from pg_hba_file_rules order by line_number;

然后检查 DM 到 5432 端口以及防火墙。修改 pg_hba.conf 后要执行 pg_reload_conf() 或按规范重启。

psqlODBC 编译出现 PG_DIAG_* undeclared
#

说明 --with-libpq 指向的 PostgreSQL 客户端头文件过旧。不要只替换 libpq.so,应同时安装匹配版本的头文件与库,并重新执行 configuremake cleanmake

DM 找不到 libodbc.solibpq.so
#

优先使用 ld.so.conf.d + ldconfig

ldconfig -p | grep -E 'libodbc|libpq'
ldd /usr/local/psqlodbc-16.00.0000/lib/psqlodbcw.so

附件手册提供了把 libodbc.solibodbcinst.solibodbccr.so 复制到 DM bin 目录的办法。为避免覆盖 DM 自带库,本文优先采用系统动态库配置;仅在得到厂商建议并完成回归测试后再复制库文件。

3.10 PostgreSQL LINK 验证结果#

--with-libpq 固定了编译时使用的 PostgreSQL 客户端版本,ldd 也确认运行时加载同一套 libpqisql 和 DM LINK 均返回 3 行、金额合计 721.50,中文和时间戳正常。升级 psqlODBC 或 libpq 后,需要重新检查头文件路径、共享库路径和 DM 远程查询结果。

附录 A:迁移后如何分层核对数据
#

DBLINK 建好后,先用低成本聚合确定差异范围,再比较明细。这样可以减少远程扫描量,也便于判断问题出在迁移批次、业务字段还是核对时间窗口。

A.1 第一层:行数、金额、最大更新时间
#

行数可暴露漏迁或重复,金额等业务汇总值可发现内容偏差,最大更新时间可帮助判断两端是否使用同一截止点。以 MySQL 为例:

select 'TARGET' side,
       count(*) rows_count,
       sum(amount) amount_sum,
       max(update_time) max_update_time
  from MIGRATION_CHECK_DM
union all
select 'SOURCE' side,
       count(*) rows_count,
       sum("amount") amount_sum,
       max("update_time") max_update_time
  from "migration_check"@"MYSQL_LINK";

Oracle 和 PostgreSQL 只需替换远程对象名与列名大小写。

本次实测把三套源表的结果与 DM 目标测试表聚合对比,全部为 PASS:

ORACLE      target_count=3  source_count=3  target_amount=601.50  source_amount=601.50  PASS
MYSQL       target_count=3  source_count=3  target_amount=661.50  source_amount=661.50  PASS
POSTGRESQL  target_count=3  source_count=3  target_amount=721.50  source_amount=721.50  PASS

A.2 第二层:双向差集
#

目标集 MINUS 源集 只能发现目标端独有的行,反向差集才能发现源端独有的行。两个方向合并后,diff_rows=0 才表示所选字段集合一致:

select count(*) as diff_rows
  from (
        (select id,biz_code,amount,note
           from MIGRATION_CHECK_DM
         minus
         select "id","biz_code","amount","note"
           from "migration_check"@"MYSQL_LINK")
        union all
        (select "id","biz_code","amount","note"
           from "migration_check"@"MYSQL_LINK"
         minus
         select id,biz_code,amount,note
           from MIGRATION_CHECK_DM)
       ) d;

本次实测 diff_rows=0

对于 CLOB/BLOB、浮点数、跨字符集 CHAR、不同时区的时间戳,不建议直接做整行差集。可先在两端按统一规则转换,再按主键分批比较业务字段。

A.3 第三层:按主键分批核对
#

大表不要直接通过 DBLINK 做无条件全表扫描。按主键或业务日期分批:

select "id","biz_code","amount","note"
  from "migration_check"@"MYSQL_LINK"
 where "id" between 1 and 100000
 order by "id";

每批应记录:

  • 起止主键;
  • 行数;
  • 金额/数量等业务汇总;
  • 差异行数;
  • 核对时间点和源库快照边界。

如果源端仍有写入,应先定义一致的截止时间或使用数据库快照。否则核对期间新增的数据会被误判为迁移差异。

附录 B:上线前的安全与运维检查
#

  1. 每个源库使用独立只读账号,只授权需要核对的库、模式和表。
  2. 限制网络来源。MySQL 用户绑定 DM IP,PostgreSQL 使用 /32 HBA,Oracle 配合防火墙或访问控制。
  3. odbc.ini 含明文密码,至少设置为 root:dinstall、权限 0640,并限制备份和日志采集范围。
  4. 只有单个 DM 用户需要访问时,优先创建私有 LINK。PUBLIC LINK 会扩大可使用该连接的账号范围。
  5. ODBC 链路先用 isql 验证 DSN,再从 DM 会话验证数据类型、中文和时间字段。
  6. 按主键或日期分段,只选择核对所需列,避免把远程大表全部拉到 DM。
  7. LINK 用于只读核对,不承担高频业务写入和复杂分布式事务。
  8. 保存 DM 构建号、驱动版本、glibc、ldd 输出和介质哈希,便于复现与回滚。
  9. DM 补丁、驱动或源库升级后,重新测试数值、时间、中文、NULL、LOB 和异常长字段。
  10. 核对结束后按变更流程删除临时 LINK,并回收或锁定源端账号。

附录 C:实验对象清理命令
#

确认不再需要实验对象后再执行,生产环境必须走审批:

-- DM
drop public link "ORA_LINK";
drop public link "MYSQL_LINK";
drop public link "PG_LINK";
-- Oracle
drop user DM_DBLINK cascade;
-- MySQL
drop user 'dm_dblink'@'192.168.17.37';
drop database dblink_lab;
-- PostgreSQL:先终止或关闭使用该库的会话
drop database dblink_lab;
drop role dm_dblink;

结论
#

本次实验中,Oracle 11.2、MySQL 5.7 和 PostgreSQL 16.3 都能通过 DM LINK 完成只读核对,中文、数值和时间字段查询正常。

部署时先确认操作系统与客户端兼容性,再检查网络和源端权限。Oracle 继续检查 OCI 动态库;MySQL 和 PostgreSQL 继续检查驱动、DSN 与 isql。这些检查通过后,从 DM 会话查询实际业务字段,以查询结果判定当前版本组合是否可用。

LINK 用完即删,源端权限随之回收。把它作为短期核对通道,不长期保留跨库访问路径。