場景:現場庫到前置庫。
思考:使用觸發器?
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、通過資料字典得到表的資料型別
程式碼中的dictionary.sql
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賬戶