場景:現場庫到前置庫。
思考:使用觸發器?
1、侵入性解決方案
2、需要時各種配置,不需要時又是各種配置
Change Data Capture:捕捉變化的數據,通過日志監測並捕獲數據庫的變動(包括數據或數據表的插入,更新,刪除等),將這些變更按發生的順序完整記錄下來,寫入到消息中間件中或者通過其他途徑分發出去。
與觸發器相比,通過日志監控的好處:
-
1、對原庫基本無侵入性,不需要像觸發器一樣,對原庫進行操作。
-
2、可以針對整庫或者庫中的表進行監控,比觸發器更加靈活高效,避免監控表比較多的情況的頻繁的建觸發器
說明
關於logminer:
所有對用戶數據和數據字典的改變都記錄在Oracle的Redo Log中,因此,Redo Log包含了所有進行恢復操作所需要的信息。但是,原始的Redo Log文件無法看懂,所以,Oracle從8i以后提供了一個非常有用的分析工具,稱為LogMiner。使用該工具可以輕松獲得Redo Log文件(包含歸檔日志文件)中的具體內容。
關於代碼:全部寫到一個java方法下,主要演示所有過程,關鍵問題處理,封裝留給你們自己進行。
關於參考:主要參考了debezium和一些國外開源的實現,但是這些都沒有支持clob大字段和blob二進制字段,同時也沒考慮一些特殊情況,我在平時的測試積累中解決了此塊的內容,故一起開源分享出來。
Github地址
https://github.com/nengm/OracleCDCByLogminer
前置步驟
Oracle:通過開源logminer進行日志分析,支持大字符串,二進制。
目前只針對在線日志分析,離線的由於需要考慮log大小等,留給以后處理。
開啟歸檔日志,這邊步驟主要是為了能夠使用logminer
以數據庫系統管理員sys as sysdba登錄
SQL> shutdown immediate; 關閉數據庫
SQL> startup mount; 啟動數據庫到mount狀態
SQL> alter database archivelog; 啟動歸檔模式
SQL> alter database open;啟動數據庫
SQL> alter system switch logfile;切換日志文件
查看數據字典表或視圖權限
GRANT SELECT_CATALOG_ROLE TO [用戶名];
執行系統所有包權限
GRANT EXECUTE_CATALOG_ROLE TO [用戶名];
創建會話權限
GRANT CREATE SESSION TO [用戶名];
選擇任何事務的權限
GRANT SELECT ANY TRANSACTION TO [用戶名];
對於12c及以上,還需要對pdb用戶進行一些設置,具體遇到再百度下。
分析過程
1、拿到當前最大位點
2、開啟logminer分析
如果ENDSCN和STARTSCN沒有超過步長,ENDSCN就拿當前的最大位點。
begin
DBMS_LOGMNR.START_LOGMNR(
STARTSCN => 586613478,
ENDSCN => 586613490,
OPTIONS =>
DBMS_LOGMNR.SKIP_CORRUPTION
+DBMS_LOGMNR.NO_SQL_DELIMITER
+DBMS_LOGMNR.NO_ROWID_IN_STMT
+DBMS_LOGMNR.DICT_FROM_ONLINE_CATALOG
+DBMS_LOGMNR.CONTINUOUS_MINE
+DBMS_LOGMNR.COMMITTED_DATA_ONLY
+DBMS_LOGMNR.STRING_LITERALS_IN_STMT
);
end;
3、通過數據字典得到表的數據類型
4、根據配置的白名單進行信息刪選
SELECT
*
FROM
V$LOGMNR_CONTENTS
WHERE(SEG_OWNER = 'EPOINT' AND TABLE_NAME = 'BASEINFO' AND COMMIT_SCN >=0)
5、分析
1、insert語句(帶大字段和圖片)
大字段和圖片都通過存儲過程得到。
我們根據csf看是否超過4000個字節,如果超過csf為0,我們把所有的sql先組裝到一起,然后通過信息組裝出一個guid,存入map,這樣后面就能找到對應的EMPTY_CLOB()對應的值了。
//用xid、ownerName、tableName、columnString唯一標識當前二進制字段的guid
//#!>-<!#為分隔符
//例如:99001800E16A0000#!>-<!#EPOINT#!>-<!#BASEINFO1#!>-<!#IMAGE
2、update語句(帶大字段和圖片)
update "EPOINT"."BASEINFO" set "NAME" = '蘇愛毓', "BIRTHDAY" = TIMESTAMP ' 1977-03-17 17:22:59', "AGE" = 3, "ADDRESS" = UNISTR('\6FB3\95E8\516B\885718\53F7-8-6') where "ROWGUID" = 'b73af60a-cdda-4702-8f28-0d707c0245a1' and "NAME" = '法貞鳳' and "BIRTHDAY" = TIMESTAMP ' 1978-04-16 09:21:46' and "AGE" = 61 and "ADDRESS" = UNISTR('\8BF8\57CE\5927\53A674\53F7-6-8')
下面緊接着是他要處理的大字段和二進制。
程序中通過下面的guid判斷是否是一批數據,然后把檢測到的大字段或者二進制與之關聯。
//用xid、ownerName、tableName、columnString唯一標識當前二進制字段的guid
//#!>-<!#為分隔符
//例如:99001800E16A0000#!>-<!#EPOINT#!>-<!#BASEINFO1#!>-<!#IMAGE
注意:
我們再測試下,讓startscn加1
可以看到無法分析出數據了,所以我們程序需要處理掉這種情況,遇到這種情況最簡單的辦法就是startscn要往回退一點,也注意不能形成死循環
其實主要是通過這些進行流程的分析處理,里面會遇到很多的坑。
測試實現
配置:由於測試整個過程,暫時單表,多表只要改造下。
1、配置
2、啟動
3、插入一條數據
主要在11g在測試,12c做了兼容,而且要使用cdb賬戶
11g
插入mysql中
5、更新
oracle
更新完mysql
6、插入2000條測試
oracle
mysql目標數據庫