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;
写在最后
哪位大佬如若发现文章存在纰漏之处或需要补充更多内容,欢迎留言!!!