【背景】
使用OGG同步MYSQL数据到ORACLE,如果表没有主键,那么此时使用所有列作为条件来更新或者删除数据,MYSQL里面存在空字符串,同步到ORACLE数据库时转换成空(NULL),注意这个不是在OGG层转换,而是依赖数据库的转换,那么此时更新或者删除会遇到非常经典错误1403(找不到数据),注意触发场景是表没有主键且更新或者删除时存在空字符串。以下是模拟过程以及几种方案。
【表结构】
show create table xiaoxu\G*************************** 1. row ***************************Table: xiaoxuCreate Table: CREATE TABLE `xiaoxu` (`RK` varchar(30) NOT NULL ,`QTY` decimal(9,0) DEFAULT NULL,`MEMO` varchar(1000) DEFAULT NULL,`EXT1` varchar(255) DEFAULT NULL,`EXT2` varchar(255) DEFAULT NULL,`ORDERTIME` datetime DEFAULT NULL) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
【MYSQL插入构造数据】
INSERT INTO `xiaoxu` values ('20095527III20211230',-1000,'20210104setup','',NULL,now());Query OK, 1 row affected (0.00 sec)select * from xiaoxu;+---------------------+-------+---------------+------+------+---------------------+| RK | QTY | MEMO | EXT1 | EXT2 | ORDERTIME |+---------------------+-------+---------------+------+------+---------------------+| 20095527III20211230 | -1000 | 20210104setup | | NULL | 2022-01-04 20:02:11 |+---------------------+-------+---------------+------+------+---------------------+1 row in set (0.00 sec)
【ORACLE OGG插入数据】
备注:通过打印SQL能够直观观察
1、参数配置很简单:
replicat repm2oxsetenv ( NLS_LANG ="AMERICAN_AMERICA.AL32UTF8")setenv (ORACLE_HOME="/data/app/oracle/product/11.2.0/dbhome_1")USERID ogg, PASSWORD ***dboptions suppresstriggersDBOPTIONS DEFERREFCONSTNOBINARYCHARSNODYNSQLSHOWSYNTAXmap ytmat.xiaoxu, target ytmat.xiaoxu;
2、[os层来启动否则会报错]
[oracle@ localhost goldengate]$ ./replicat paramfile ./dirprm/repm2ox.prmINSERT /*+ RESTRICT_ALL_REF_CONS */ INTO "YTMAT"."XIAOXU"("RK","QTY","MEMO","EXT1","EXT2","ORDERTIME") VALUES('20095527III20211230','-1000','20210104setup','',NULL,TO_DATE('2022-01-04 20:02:11','YYYY-MM-DD HH24:MI:SS'))Statement length: 221(S)top display, (K)eep displaying (default):这里回车即可
3、验证数据
备注:同步oracle后,mysql里面空字符串与NULL都变成空.


查询空字符串是没有结果返回

【MYSQL模拟数据】
update xiaoxu set QTY='10000' where RK='20095527III20211230';Rows matched: 1 Changed: 1 Warnings: 0select * from xiaoxu;+---------------------+-------+---------------+------+------+---------------------+| RK | QTY | MEMO | EXT1 | EXT2 | ORDERTIME |+---------------------+-------+---------------+------+------+---------------------+| 20095527III20211230 | 10000 | 20210104setup | | NULL | 2022-01-04 20:02:11 |+---------------------+-------+---------------+------+------+---------------------+1 row in set (0.00 sec)
【ORACLE OGG更新数据】
备注:通过打印SQL能够直观观察,到这里OGG是无法正常继续下去了,提示经典错误1403.找不到数据。
UPDATE /*+ RESTRICT_ALL_REF_CONS */ "YTMAT"."XIAOXU" x SETx."RK" = '20095527III20211230',x."QTY" = '10000',x."MEMO" = '20210104setup',x."EXT1" = '',x."EXT2" = NULL,x."ORDERTIME" =TO_DATE('2022-01-04 20:02:11','YYYY-MM-DD HH24:MI:SS')WHERE x."RK"='20095527III20211230' ANDx."QTY"='-1000' AND x."MEMO"='20210104setup'AND x."EXT1"='' AND x."EXT2" IS NULL ANDx."ORDERTIME"=TO_DATE('2022-01-04 20:02:11','YYYY-MM-DD HH24:MI:SS')AND ROWNUM = 1Statement length: 446(S)top display, (K)eep displaying (default):从这里可以清晰看到OGG更新还是使用空字符串去匹配数据,显然无法匹配的.直接1403错误2022-01-04 20:15:03 WARNING OGG-01004 Aborted groupedtransaction on YTMAT.XIAOXU, Database error 1403(OCI Error ORA-01403: no data found, SQL <UPDATE /*+RESTRICT_ALL_REF_CONS */ "YTMAT"."XIAOXU" x SET x."RK" = :a6,x."QTY" = :a7,x."MEMO" = :a8,x."EXT1" = :a9,x."EXT2" = :a10,x."ORDERTIME" = :a11 WHERE x."RK" = :b0 AND x."QTY" = :b1 ANDx."MEMO" = :b2 AND x."EXT1" = :b3 AND x."EXT2" is NULL ANDx."ORDERTIME" = :b5 AND ROWNUM = 1>).
【针对以上解决方案】
1、使用handlecollisions来处理异常,此时会造成重复数据,会把更新转换成插入,造成数据异常,这个方案不适合
2、如果能够几个字段来确定唯一值,使用keycols(aa,bb),如果不涉及到空字符串,此时通过创建唯一索引来解决这个问题.--快速解决方案
3、如果无法通过几个字段来确定唯一值,此时需要在mysql端禁止使用空字符串来规避这个问题.因为涉及异构数据转换问题,所以我们需要前期针对不同数据库处理逻辑的不同来规范研发操作.否则同步数据与数据验证是比较麻烦的事情.--从根本解决方案
4、如果OGG层能够支持转换空字符串转换成NULL,目前这个参数我没有找到,如果大家知道有参数能够进行转换或者其他方案,欢迎交流.
文章转载自DB说,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。




