CVT(数据清洗转换)是 DMDRS 的重要功能模块,支持在数据同步过程中对
INSERT、UPDATE、DELETE 操作进行实时改写。本文带你完成 CVT
环境搭建,并编写.cvt脚本验证三种 DML 操作的转换效果。
CVT(Cleansing & Transformation)是 DMDRS 的数据清洗转换模块,在 EXEC
端以行记录为单位,对同步过来的每一条 DML 操作进行转换处理。
核心能力:
为 INSERT 操作添加标识列和时间戳
将 UPDATE 拆分为两条 INSERT(修改前 + 修改后)
将 DELETE 转为 INSERT(保留删除前的数据)
适用场景:过程数据同步、操作审计、历史追溯。
DMDRS 主备环境已搭建完成(参考《DMDRS 主备搭建完全指南》)
EXEC 模块正常运行,能接收 CPT 投递的数据
在 EXEC 工作目录下创建cvt_scripts文件夹:
cd /data/dmdrs5/bin_exec_dm8_5345
mkdir cvt_scripts
编辑exec.xml,添加cvt_dir配置项:
<exec>
<!-- 其他配置保持不变 -->
<cvt_dir>cvt_scripts</cvt_dir>
</exec>
完整示例:
<exec>
<name>exec_dm8</name>
<login>
<dbtype>dm8</dbtype>
<server>192.168.21.135</server>
<user>TEST_DB</user>
<pwd>Dameng123</pwd>
<port>5237</port>
</login>
<cvt_dir>cvt_scripts</cvt_dir>
</exec>
cvt_scripts/
├── global.glb # 全局变量定义
└── full_cvt.cvt # DML 转换规则
GLOBAL
DECLARE
g_total_rows INT;
BEGIN
g_total_rows := 0;
DRS_SYS.PUT_LINE(’>>> CVT 初始化完成’);
END;
CLEAN
BEGIN
DRS_SYS.PUT_LINE(’>>> CVT 清理完成,总处理记录数: ’ ||
g_total_rows);
END;
TABLE DMDRS.EMPL1
DECLARE
old_cols DRS.DML_COL_ARR;
new_cols DRS.DML_COL_ARR;
i INT;
v_op VARCHAR(16);
BEGIN
v_op := UPPER(op.#OP);
g_total_rows := g_total_rows + 1;
DRS_SYS.PUT_LINE(’>>> 第 ’ || g_total_rows || ’ 条, 操作: ’
|| v_op);
– INSERT: 添加标识 I 和时间戳
IF v_op = ‘INSERT’ THEN
op.ADD_COL(‘BIAOSHI’, ‘I’);
op.ADD_COL(‘OP_TIME’, SYSDATE());
op.exec();
RETURN;
– UPDATE: 拆分为两条 INSERT(D + I)
ELSIF v_op = ‘UPDATE’ THEN
old_cols := op.GET_OLDCOLS();
new_cols := op.GET_NEWCOLS();
– 旧数据 -> INSERT, 标记 D
op.#OP := ‘INSERT’;
op.SET_COLS(old_cols);
op.ADD_COL(‘BIAOSHI’, ‘D’);
op.ADD_COL(‘OP_TIME’, SYSDATE());
op.exec();
– 新数据 -> INSERT, 标记 I, 补全未修改列
op.#OP := ‘INSERT’;
op.SET_COLS(new_cols);
FOR i IN 1…old_cols.SIZE LOOP
IF op.HAS_NEWCOL(old_cols[i].NAME) = 0 THEN
op.ADD_COL(old_cols[i].NAME, old_cols[i].VALUE);
END IF;
END LOOP;
op.ADD_COL(‘BIAOSHI’, ‘I’);
op.ADD_COL(‘OP_TIME’, SYSDATE());
op.exec();
RETURN;
– DELETE: 转为 INSERT, 标记 D
ELSIF v_op = ‘DELETE’ THEN
old_cols := op.GET_OLDCOLS();
op.#OP := ‘INSERT’;
op.SET_COLS(old_cols);
op.ADD_COL(‘BIAOSHI’, ‘D’);
op.ADD_COL(‘OP_TIME’, SYSDATE());
op.exec();
RETURN;
ELSE
DRS_SYS.PUT_LINE(’>>> 未知操作: ’ || v_op);
RETURN;
END IF;
END;
由于 UPDATE 会拆成两条
INSERT,目标表必须支持同一业务主键的多版本共存。推荐使用自增列作为主键:
– 目标表(在目标端执行)
CREATE TABLE TEST_DB.EMPL1_TARGET (
SEQ_ID BIGINT AUTO_INCREMENT PRIMARY KEY,
ID INT,
NAME VARCHAR(50),
AGE INT,
SALARY DEC(10,2),
BIAOSHI VARCHAR(10),
OP_TIME TIMESTAMP
);
脚本中的op.exec()默认使用源表名EMPL1,如果要写入目标表EMPL1_TARGET,修改为op.exec(EMPL1_TARGET)即可。
cd /data/dmdrs5/bin_exec_dm8_5345
pkill -9 -f “drsvr.*exec”
rm -rf CACHE_* LLOG_* # 清缓存,重新加载脚本
nohup ./drsvr exec.xml >> exec.log 2>&1 &
查看脚本加载状态:
grep “cvt load success” exec.log
在源端执行以下操作:
– 1. INSERT
INSERT INTO DMDRS.EMPL1 VALUES (1, ‘张三’, 25, 5000.00);
COMMIT;
– 2. UPDATE
UPDATE DMDRS.EMPL1 SET AGE = 26, SALARY = 5500.00 WHERE ID = 1;
COMMIT;
– 3. DELETE
DELETE FROM DMDRS.EMPL1 WHERE ID = 1;
COMMIT;
在目标端查询结果:
SELECT SEQ_ID, ID, NAME, AGE, SALARY, BIAOSHI, OP_TIME
FROM TEST_DB.EMPL1_TARGET ORDER BY SEQ_ID;
预期结果:
SEQ_ID ID NAME AGE SALARY BIAOSHI OP_TIME
1 1 张三 25 5000.00 I 2026-08-24
10:00:01
2 1 张三 25 5000.00 D 2026-08-24
10:00:05
3 1 张三 26 5500.00 I 2026-08-24
10:00:05
4 1 张三 26 5500.00 D 2026-08-24
10:00:10
共 4 条记录:INSERT (I) → UPDATE 旧数据 (D) → UPDATE 新数据 (I) → DELETE
(D),完整记录了该数据的所有变更历史。
DRS_SYS.PUT_LINE需要PRINT_TRACE掩码才能输出。在exec.xml中添加:
<log_mask>PRINT_TRACE</log_mask>
tail -f exec.log | grep “>>>”
原因:EXEC 缓存了旧脚本。
解决:停止 EXEC,删除CACHE_*和LLOG_*目录后重启。
原因:目标表主键为业务主键,第二条 INSERT 被主键冲突拒绝。
解决:改用自增列作为主键(参考第5节)。
原因:log_mask未包含PRINT_TRACE。
解决:在exec.xml中配置<log_mask>PRINT_TRACE</log_mask>。
本文完成了 CVT 环境的搭建,并通过一个完整的.cvt脚本验证了
INSERT、UPDATE、DELETE 三种 DML 操作的转换效果。核心要点:
目标表使用自增主键,承载多版本数据
UPDATE 拆分时注意补全未修改的列
调试时记得配置PRINT_TRACE掩码
有了这个基础,你可以进一步扩展 CVT 脚本,实现更复杂的数据转换逻辑。
文章
阅读量
获赞
