实验日期: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.37 | CentOS 7 x86_64,glibc 2.17 | DM8,ID_CODE=03134284336-20250117-257733-20132 | UTF-8,端口 5236 |
| Oracle 源端 | 192.168.17.11 | Oracle Linux 7.9 x86_64 | Oracle 11.2.0.4,服务名 orcl | ZHS16GBK,端口 1521 |
| MySQL 源端 | 192.168.17.57 | CentOS 7 x86_64 | MySQL 5.7.29 | 实验库 dblink_lab 使用 utf8mb4,端口 3306 |
| PostgreSQL 源端 | 192.168.17.16 | Rocky Linux 9.3 x86_64 | PostgreSQL 16.3 | UTF8,端口 5432 |
DM 端实际安装的客户端组件如下:
| 组件 | 实测版本 | 安装目录 |
|---|---|---|
| Oracle Instant Client | 19.31 | /opt/oracle/instantclient_19_31 |
| unixODBC | 2.3.9 | /usr/local/unixODBC-2.3.9 |
| MySQL Connector/ODBC | 5.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 |
| psqlODBC | 16.00.0000 | /usr/local/psqlodbc-16.00.0000 |
三条 LINK 的验证结果#
| LINK | 源表行数 | 金额合计 | 中文字段 | 聚合核对 |
|---|---|---|---|---|
ORA_LINK | 3 | 601.50 | 正常 | PASS |
MYSQL_LINK | 3 | 661.50 | 正常 | PASS |
PG_LINK | 3 | 721.50 | 正常 | PASS |
三条 LINK 均从 DM 会话读取成功。MySQL 测试表随后执行双向 MINUS,明细差异行数为 0。验证内容包括连接、对象访问、数值聚合和中文转换。
介质下载与校验#
官方下载入口:
- Oracle Instant Client for Linux x86-64
- MySQL Connector/ODBC 下载与归档
- PostgreSQL 16.3 源码
- psqlODBC 历史源码
- unixODBC 下载页
下表记录本次实验实际使用的介质。部署前核对 SHA-256,可以排除下载不完整或文件被替换的问题。
| 文件 | SHA-256 |
|---|---|
instantclient-basic-linux.x64-19.31.0.0.0dbru.zip | a4433867b83d170d093198651ecd6f74db1030168835b96e88bd605e4c900de3 |
mysql-connector-odbc-5.3.14-linux-glibc2.12-x86-64bit.tar.gz | e7ca39163810b39e2e5925a7c877187536a8ed4f129dc2c39d073351b116a446 |
postgresql-16.3.tar.gz | bd3798c399bc1b6d08b94340f9dd7a75a30a7fa076788ef2f4848be2be6a5fc5 |
psqlodbc-16.00.0000.tar.gz | afd892f89d2ecee8d3f3b2314f1bd5bf2d02201872c6e3431e5c31096eca4c8b |
unixODBC-2.3.9.tar.gz | 52833eac3d681c8b0c9a5a65f2ebd745b3a964f208fc748f977e44015a31b207 |
下载示例:
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 sysdbaselect 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.1ldd 会列出 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 连接丢失#
依次检查:
- DM 到 Oracle 的 1521 端口;
- 用户名和密码,尤其是加引号后大小写敏感的账号;
lsnrctl status中的服务名,而不是只看实例名;- 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 -d2.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 驱动返回的数据类型元数据不匹配。本次的处理路径是:
- 逐列查询确认不是单个业务字段导致;
- 用 ANSI/Unicode 两种 8.0.29 驱动复测;
- 结合 MySQL 5.7 版本切换到 Connector/ODBC 5.3.14;
- 重新执行
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 验证结果#
ldd、isql 和 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_NAME、PG_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_labcreate 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 install3.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
ldconfig3.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.ini3.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,应同时安装匹配版本的头文件与库,并重新执行 configure、make clean、make。
DM 找不到 libodbc.so 或 libpq.so#
优先使用 ld.so.conf.d + ldconfig:
ldconfig -p | grep -E 'libodbc|libpq'
ldd /usr/local/psqlodbc-16.00.0000/lib/psqlodbcw.so附件手册提供了把 libodbc.so、libodbcinst.so、libodbccr.so 复制到 DM bin 目录的办法。为避免覆盖 DM 自带库,本文优先采用系统动态库配置;仅在得到厂商建议并完成回归测试后再复制库文件。
3.10 PostgreSQL LINK 验证结果#
--with-libpq 固定了编译时使用的 PostgreSQL 客户端版本,ldd 也确认运行时加载同一套 libpq。isql 和 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 PASSA.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:上线前的安全与运维检查#
- 每个源库使用独立只读账号,只授权需要核对的库、模式和表。
- 限制网络来源。MySQL 用户绑定 DM IP,PostgreSQL 使用
/32HBA,Oracle 配合防火墙或访问控制。 odbc.ini含明文密码,至少设置为root:dinstall、权限0640,并限制备份和日志采集范围。- 只有单个 DM 用户需要访问时,优先创建私有 LINK。PUBLIC LINK 会扩大可使用该连接的账号范围。
- ODBC 链路先用
isql验证 DSN,再从 DM 会话验证数据类型、中文和时间字段。 - 按主键或日期分段,只选择核对所需列,避免把远程大表全部拉到 DM。
- LINK 用于只读核对,不承担高频业务写入和复杂分布式事务。
- 保存 DM 构建号、驱动版本、glibc、
ldd输出和介质哈希,便于复现与回滚。 - DM 补丁、驱动或源库升级后,重新测试数值、时间、中文、NULL、LOB 和异常长字段。
- 核对结束后按变更流程删除临时 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 用完即删,源端权限随之回收。把它作为短期核对通道,不长期保留跨库访问路径。
