首页 > 数据库 >debezium同步Oracle数据时,更新操作只有被变更字段,其余字段值为null,主键ID值为0

debezium同步Oracle数据时,更新操作只有被变更字段,其余字段值为null,主键ID值为0

时间:2023-12-20 17:35:27浏览次数:46  
标签:段值 启用 补充 值为 日志 data 主键 supplemental

1.情景展示

使用debezium的Oracle插件(io.debezium.connector.oracle.OracleConnector)自动读取Oracle的归档日志。

当我对Oracle数据库受监控的表(待同步表),进行更新操作后,debezium会自动将变更记录推送到kafka当中。

新增和删除操作,数据都能同步到另一个数据库。

但是,更新操作,数据无法完成同步。

通过读取消费数据(windows)

cd ../kafka_2.13-3.5.1\bin\windows
kafka-console-consumer.bat --bootstrap-server localhost:9092 --topic 主题名称前缀.库名.表名  --from-beginning
pause

得到更新操作的具体数据

数据片段展示

"payload":{"before":{"PATIENT_ID":null,"ZS_ID":null,"CREATE_TIME":1703008226000,"UPDATE_TIME":1703008233000,"JZ_TIME":1703008236000000,"ID":"0"},"after":{"PATIENT_ID":null,"ZS_ID":null,"CREATE_TIME":1702921826000,"UPDATE_TIME":1702921833000,"JZ_TIME":1702921836000000,"ID":"0"},"source":{"version":"2.3.3.Final","connector":"oracle","name":"topic-orcl-73","ts_ms":1702895875000,"snapshot":"false","db":"ORCL","sequence":null,"schema":"用户名","table":"T_PATIENT_ZS","txId":"0b0014002cf18800","scn":"17183600513818","commit_scn":"17183600513819","lcr_position":null,"rs_id":"0x0084ca.0007c1fc.0010","ssn":0,"redo_thread":1,"user_name":"用户名"},"op":"u","ts_ms":1702895876553,"transaction":null}

说明:只展示了payload节点,最重要的信息就在这个节点中啦,其余就没有看的必要了。 

 before节点里面是变更前的数据,after节点里面是变更后的数据。

如上所示:

其一,我在数据库当中更改了CREATE_TIME,UPDATE_TIME和JZ_TIME三个字段,所以,before和after节点里面都有这三个字段的数据。

其二,其余字段由于没有变更,所以归档日志里面并没有将对应的字段值记录在内,这个很合理。(当然,如果你需要将没有发生变更的字段的值也展示出来,下面我也会讲)

其三,T_PATIENT_ZS表的主键字段是:ID,但是,我们可以发现ID字段的值一直为0。

其余字段没有变更,所以没值。但主键字段的值一直是0,这是怎么回事?

2.具体分析

其实,变更日志本身并没有错误,数据发生变更的字段就记录上,没发生变更就不记录。

虽然主键字段对于业务来说是必须的,但是,对于变更日志来说,由于主键字段的内容没有发生变化,所以,不进行记录也是很合理的。

但,对于我们想要根据日志来进行同步的人来说,这就很不合理了,怎么解决?

其实,如果你仔细看过kafka connect的输出日志的话,debezium早就给出了:日志补充的提醒,以及如何补充。

Database table 'ORCL.用户名.T_PATIENT_ZS' not configured with supplemental logging "(ALL) COLUMNS"; only explicitly changed columns will be captured. Use: ALTER TABLE 用户名.T_PATIENT_ZS ADD SUPPLEMENTAL LOG DATA (ALL) COLUMNS 

上面这段话的意思是:

T_PATIENT_ZS表没有配置补充日志(ALL)  CLOUMNS,只有内容发生变化的字段才会被捕获。

请用:ALTER TABLE 用户名.T_PATIENT_ZS ADD SUPPLEMENTAL LOG DATA (ALL) COLUMNS。

意思是:让我们在Oracle当中执行上面的这个SQL语句。

3.解决方案

出现这种情况,实际上是因为:DBA只给当前数据库开启了归档日志,却没有开启补充日志。

debezium读取的日志,其实只是变更日志,由于变更日志只记录了发生变化的字段,所以,我们需要对其进行补充。

在Oracle当中,想要对变更日志进行补充,需要我们开启补充日志。

查询数据库是否启用补充日志

SELECT supplemental_log_data_min, supplemental_log_data_pk, supplemental_log_data_all FROM v$database;

SELECT supplemental_log_data_min "启用最小补充日志", supplemental_log_data_pk "启用主键补充日志", supplemental_log_data_all "启用所有字段补充日志" FROM v$database;

如果主键补充日志没有启用,请按照如下SQL进行修改。

有两种解决方案。 

只补全主键日志

主键补充日志的作用是在update命令的重做记录中添加被修改行的主键字段的旧值,这是无条件式的补充日志,所谓无条件即无论主键字段本身是否被update命令修改,其旧值都会被记录。 

但是,并不是每张表都一定要有主键。

如果存在没有主键的表,则主键字段由长度最小的非空唯一索引字段代替。

如果表结构中一个非空索引字段都没有,那么oracle将被修改行的所有字段(除了lob和long类型)的旧值都记录下来(这将导致重做记录的数据量暴涨,所以如果要启用主键补充日志,又为了维护lgwr和重做日志,每张表最好具有主键或至少一个非空唯一字段)。

启用主键补充日志:

alter database add supplemental log data (primary key) columns;

我需要的就是这个。

补全所有字段日志

全体字段补充日志和主键补充日志一样为无条件式的,无论哪个字段被update命令修改,所有字段(除了lob,long类型)的旧值都将被记录,其效果相当于启用了主键补充日志的前提下既没有主键也没有非空唯一索引字段的情况,这样几乎所有的表数据都搬到了重做日志中,不但存在当前的,历史数据也没有丢下(对恢复操作来说比较好,但是对于lgwr和磁盘空间就不是太好,一般很少启用这样的日志)。

虽然不建议,但可能有的人会有这种需求。

alter database add supplemental log data (all) columns; 

这个不仅主键字段内容会被记录,其余没有发生变更的字段也都将被记录在日志当中。

4.验证

按需求执行上述SQL(二选一即可),查看数据库是否启用补充日志。

如果补充日志没有启用成功,可以进行如下操作。

提交进行的更改

ALTER SYSTEM SWITCH LOGFILE;

在这里,我只启用了主键补充日志。

对于我而言,在更新的时候,现在缺的就是主键,有了主键,我就可以将变更数据同步到其它数据库当中。

再次执行更新操作后,查看消费数据,就可以这次主键字段,已经有值啦。

5.拓展 

说明:

补充日志生效的前提是:开启归档日志,如果没有开启归档日志,何谈补充日志。

Oracle补充日志的分类

最小补充日志

最基本的一种数据库级补充日志。

查询是否启用最小补充日志

select supplemental_log_data_min min from v$database;

开启最小补充日志

alter database add supplemental log data;

关闭最小补充日志

alter database drop supplemental log data;

标识关键字段补充日志

共有四种类型:主键、唯一索引、外键、全体字段补充日志。

标识关键字段补充日志必须建立在最小补充日志的基础上,当其被启用时,若最小补充日志尚未启用,则oracle会隐式开启最小补充日志;

同样,在没有关闭标识关键字段补充日志的时候,不能先关闭最小补充日志。

主键补充日志

上面已经介绍,此处不再赘述,以下为补充内容。

以单个表为单位启用

ALTER TABLE 用户名.表名 ADD SUPPLEMENTAL LOG DATA (PRIMARY KEY) COLUMNS;

一次性对数据库所有表启用

ALTER DATABASE ADD SUPPLEMENTAL LOG DATA (PRIMARY KEY) COLUMNS;
唯一索引补充日志

条件:只有当唯一字段被update时,才会记录该字段被修改前的值,因为唯一键索引是能够建立在多个字段上的。

alter database add supplemental log data (unique) columns;
外键补充日志

条件:外键补充日志和唯一索引补充日志一样同为有条件式的,只有当外键字段被update命令修改时,其修改前的旧值才会被记录。

alter database add supplemental log data (foreign key) columns;
全体字段补充日志

上面已经介绍,此处不再赘述,以下为补充内容。

以单个表为单位启用

ALTER TABLE 用户名.表名 ADD SUPPLEMENTAL LOG DATA (PRIMARY KEY) COLUMNS;

一次性对数据库所有表启用

ALTER DATABASE ADD SUPPLEMENTAL LOG DATA (ALL) COLUMNS;

 

写在最后

  哪位大佬如若发现文章存在纰漏之处或需要补充更多内容,欢迎留言!!!

 相关推荐:

标签:段值,启用,补充,值为,日志,data,主键,supplemental
From: https://www.cnblogs.com/Marydon20170307/p/17917072.html

相关文章

  • mybatis获取insert操作自增主键值
    大家好,我是joker,希望你快乐。在日常使用mybatis时,经常会遇到数据库表的主键是自增id的情况。数据库的表结构又设计成主子表的情况,在插入主表数据后,为了维护主子表关系,通常需要获取插入主表中的自增id。代码示例mapper.xml<insertid="insertCity"parameterType="City"useG......
  • Postgresql中自增主键序列的使用以及数据传输时提示:错误:关系"xxx_xx_xx_seq"不存在
    场景Postgresql在Windows中使用pg_dump实现数据库(指定表)的导出与导入:https://blog.csdn.net/BADAO_LIUMANG_QIZHI/article/details/135011801上面讲使用pg_dump进行postgresql的导出与导入。如果使用Navicat可以直接连接两个库,则可直接使用数据传输功能。但是在传输某个表......
  • sqlserver 查询一个表的主键是哪些表的外键
    select object_name(a.parent_object_id)as '表名'from sys.foreign_keys awhere a.referenced_object_id=object_id('XXX')--XXX为需要查询的表......
  • 主键和外键
    主键主键(PrimaryKey):主键是用于唯一标识表中每一行记录的字段或字段组合。每个表只能有一个主键,且主键的值不能重复且不能为NULL。主键通常用于加速数据检索,因为数据库系统会为主键创建索引。在MySQL中,可以在表的创建时或之后通过ALTERTABLE语句添加主键。在创建表时定义......
  • Mysql count(*)、count(1)、count(主键)、count(普通字段) 性能对比
    count(*):底层会转化为count(0)来处理,默认横向扫描聚集索引树,如果有二级索引就扫描二级索引树(因为二级索引树更小,扫描成本低),扫描到一行记录之后,将该记录返回给Server层,由于参数是0,不为NULL,所以不需要读取记录中的任何字段,直接将 count变量加1count(1):处理......
  • 分布式主键
     核心概念::ShardingSpherehttps://shardingsphere.apache.org/document/current/cn/features/sharding/concept/ 分布式主键传统数据库软件开发中,主键自动生成技术是基本需求。而各个数据库对于该需求也提供了相应的支持,比如MySQL的自增键,Oracle的自增序列等。数据......
  • 金蝶云星空使用webapi查询单据附件的主键
    业务需求:查询采购价目表的附件 详细操作 一、查询单据附件查看账套单据附件 查询采购价目表的单据内码和单据体内码SELECTa.FNUMBER,a.FID,b.FENTRYID,b.FSEQFROMt_PUR_PriceListaLEFTJOINt_PUR_PriceListEntrybONa.FID=b.FIDWHEREa.FNUMBER='CGJM......
  • MyBatisPlus主键生成策略
    @[TOC]什么是主键生成策略?在数据库中,每一行数据都需要一个唯一的标识符,这就是主键。主键生成策略决定了如何为新插入的行生成这个唯一标识符。不同的数据库和框架提供了不同的主键生成策略选项。MyBatisPlus中的主键生成策略AUTO:这是默认的策略,根据数据库的不同自动选择合适的主......
  • SQL Server数据库 主键自增标识列设置为默认值重新为1
    关键代码:注意:表格里原存在有的数据自增列不会变更,变更的是重新添加后的自增列......
  • golang 根据 json path 提取字段值
    在Golang中,可以使用github.com/tidwall/gjson包来根据JSON路径提取字段值。 packagemainimport("fmt""github.com/tidwall/gjson")funcmain(){jsonStr:=`{"name":"John","age":30,......