標籤:eclipse 14. update 配置環境 package 基礎 尾碼 兩台 現在
上一文章 《__Win7 配置OGG(Oracle GoldenGate).docx》定下了 兩個目標:
給安裝的Oracle_11g 建立 兩個使用者 admin 和 root 。
admin 對應了 ADMIN 結構,建立了一個 TB_ TEST表。
root 對應了 ROOT 結構,也建立一個 TB_ TEST (表結構一摸一樣)。
當 admin.TBTEST 中的表資料 變化時,root.TB TEST 的表資料 自動同步(備份)
PS. 實際的 容災備份,肯定是 兩個 Oracle 伺服器,通過網路傳輸 備份資料 —— 各位可以想象 admin 和 root 在兩台不同伺服器 上。
當 admin.TB_ TEST 表資料發生變化時,把這種變化 傳遞給 Java、C# 程式。
當 Java、C# 程式得到 資料變化訊息時,把 資料的變化 記錄到日誌中(或者其他動作)。
其中,目標1 已經完成,我們開始嘗試 目標2
下載 OGG Adapter Java:
http://www.oracle.com/technetwork/cn/middleware/goldengate/downloads/index.html
開始配置 Java運行環境:
我開始後悔了,我的系統是 64位Win7。
我後悔自己安裝的是 32位的 Oracle。
我後悔自己安裝了兩套 JDK: C:\Program Files\Java\jdk1.8.0121 和 C:\Program Files (x86)\Java\jdk1.8.0121。
我後悔自己的OGG目錄 取了這麼長的 一個名字: D:\oracle\product\11.1.0\x86_ogg4oracle\
接下來的文章:這些坑將導致各種詭異的問題 —— 填坑指南,作者帶著你 一起踩坑一起填,在失敗中積累厚重經驗、在填坑中收穫絕對穩定。
配置環境變數:
我的電腦 64位Win7,安裝了 64位、32位 位兩種 JDK。Oracle_11g 32位,OGG 32位。
進行如下操作:
- 找到 64位 JDK目錄 —— 右鍵,“360強力刪除” —— 沒錯,強力粉碎,這源自我踩坑踩出的仇恨,粉碎,粉碎。 案頭>電腦>右鍵>屬性>進階系統設定>“進階”選項卡>環境變數。
CLASSPATH : .;%JAVAHOME%\lib\tools.jar;%JAVAHOME%\lib\dt.jar;%JAVA_HOME%\bin;
JAVAHOME : C:\Program Files (x86)\Java\jdk1.8.0121
JREHOME : C:\Program Files (x86)\Java\jre1.8.0121
Path : %JAVA_HOME%\bin;
驗證環境變數:
開啟cmd (不詳述了,cmd 都打不開,這篇文章你也不用看了)
建議重啟電腦,好像有時候,JAVA的環境變數 要重啟後 才生效 —— 重啟保平安。
開始考驗 JAVA基礎的時候了:
開啟 eclipse,建立一個 hello world 項目。匯出 jar 包。
再次驗證 java 運行環境:
你以為 這個 hello.jar 有啥用? —— 沒用!
玄學懂不懂?
安裝SQL Server 你不去上個廁所,你還想安裝成功?【上廁所,減少人為磁碟操作,SQLServer安裝程式更穩定】
你不寫個 hello word,你還想把OGG Adapter Java 配成?【就是為了驗證 java 運行環境,配置者的java基礎】
開始配置 OGG Adapter Java 【正式代碼在下面,我們要先驗證 OGG-Java 的配置環境】
回顧一下:針對 ADMIN.TB_TEST 表 —— 當資料變化時,我們的Java外掛程式要能夠 捕獲到資料變化。
產生表結構 定義檔案。【目標:得到一個 .def 尾碼的檔案(過程中的其他檔案都可以刪除)】
在 D:\Temp\ 檔案夾建立一個 文字檔 source.prm 內容如下:
運行 cmd,通過 source.prm 產生 source.def 檔案。
找到 D:\oracle\product\11.1.0\x86ogg4oracletarget\ 【目標端】雙擊運行 ggsci.exe 程式。 添加 javaue
配置 javaue
javaue.prm如下:
Extract JAVAUE
SourceDefs dirprm/source.def
getEnv (JAVA_HOME)
-- getEnv (LDLIBRARYPATH)
getEnv (PATH)
CUserExit ggjava_ue.dll CUSEREXIT PassThru IncludeUpdateBefores
GetUpdateBefores
Table ADMIN.*;
javaue.properties 如下:
gg.handlerlist=sample.SampleHandler
java.naming.provider.url=tcp://localhost:61616
java.naming.factory.initial=org.apache.activemq.jndi.ActiveMQInitialContextFactory
gg.handler.sample.type=sample.SampleHandler
goldengate.userexit.timestamp=utc
goldengate.userexit.nochkpt=true
嘗試啟動 javaue
PS.
如果出現 “不出錯”的錯誤(rpt 檔案沒有任何異常資訊),但 start javaue 視窗一閃而過,死活無法啟動。
記住如下方式:用命令列 參數模式 啟動 javaue,可以顯示 “不出錯”錯誤。
extract paramfile D:\oracle\product\11.1.0\x86_ogg4oracle_target\dirprm\javaue.prm
正式編寫 OGG Adapter Java 外掛程式代碼
建立項目 custom,添加 jar包 引用。
建立 Java檔案 SampleHandler,源碼如下:
注意:OGG 12 和 OGG 11 的代碼是完全不同的。
//---------------------------------------------------------------------------------------------------package sample; //包名稱 sample,類名稱 SampleHandler —— 有沒有讓你想到什嗎? javaue.propertiesimport java.io.*;//這是 OGG 11 的 import import com.goldengate.atg.datasource.AbstractHandler;import com.goldengate.atg.datasource.DsConfiguration;import com.goldengate.atg.datasource.DsEvent;import com.goldengate.atg.datasource.GGDataSource.Status;import com.goldengate.atg.datasource.meta.DsMetaData;import com.goldengate.atg.datasource.test.DsTestUtils.Logger;import com.goldengate.atg.datasource.meta.*;import com.goldengate.atg.datasource.*;//這是 OGG 12 的 import //import org.slf4j.Logger;//import org.slf4j.LoggerFactory;//import oracle.goldengate.datasource.AbstractHandler;//import oracle.goldengate.datasource.DsConfiguration;//import oracle.goldengate.datasource.DsEvent;//import oracle.goldengate.datasource.DsTransaction;//import oracle.goldengate.datasource.conf.DsHandler.Handler.Status;//import oracle.goldengate.datasource.meta.DsMetaData;//import oracle.goldengate.datasource.GGDataSource;public class SampleHandler extends AbstractHandler { //OGG 11 和 OGG 12 的 日誌好像不一樣, OGG 12 似乎要寫 LoggerFactory.getLogger(SampleHandler.class); private final Logger logger = com.goldengate.atg.datasource.test.DsTestUtils.Log4jLogger.getLogger(SampleHandler.class); @Override public void init(DsConfiguration conf, DsMetaData metaData) { super.init(conf, metaData); logger.info("init!"); WriteStringToFile("D:\\SampleHandler。log", "SampleHandler.init(*)"); } @Override public Status transactionCommit(DsEvent e, DsTransaction tx) { logger.info("transactionCommit!"); WriteStringToFile("D:\\SampleHandler。log", "SampleHandler.transactionCommit(*)"); return Status.OK; } @Override public void destroy() { super.destroy(); WriteStringToFile("D:\\SampleHandler。log", "SampleHandler.destroy(*)"); logger.info("destroy!"); } @Override public String reportStatus() { WriteStringToFile("D:\\SampleHandler。log", "SampleHandler.reportStatus(*)"); return "reportStatus"; } public void WriteStringToFile(String filePath, String text) { try { System.out.println(text); File file = new File(filePath); PrintStream ps = new PrintStream(new FileOutputStream(file)); //ps.println(text);// 往檔案裡寫入字串 ps.append(text);// 在已有的基礎上添加字串 } catch (FileNotFoundException e) { e.printStackTrace(); } } }//---------------------------------------------------------------------------------------------------
編譯通過,匯出 jar包:
再次啟動 javaue:
視窗再次一閃而過,啟動失敗,繼續查錯。
參考:49300853
重裝 Java環境,重新修改 4個環境變數,驗證 java 安裝環境。
java -jar D:\hello.jar
重啟電腦(或者關掉所有 cmd, ggsci 視窗),重新開啟 \x86ogg4oralcetarget\ggsci.exe 輸入命令: start mgr start javaue
現代詩:《OGG的迷惘》
那一刻,
晶瑩的淚水滑過臉龐,
我似乎,
看到了成功的希望。
蹉跎與掙紮,
糾結與迷惘。
在折騰中,我終究能走向想要的遠方。
—— 再給我一次機會,讓我再配置一次OGG。
—— 不!我選擇 死亡(罵娘)~
打油詩:《神坑OGG》
神坑最多OGG,
坑得勞資沒脾氣。
坑得勞資沒脾氣~
神坑最多OGG~
開始測試 javaue 外掛程式是否成功:
程式這次崩潰了,對比一下 兩種配置:
在下面的配置(崩潰)中,我們看到了一個路徑 dirlib/custom.jar。
我們嘗試將 eclipse 匯出的 jar 檔案 D:\Temp\custom.jar,複製到 \x86ogg4oracletarget\dirlib\ 檔案夾(dirlib 要手動建立)
再次運行,還是崩潰,還是相同的錯誤資訊:
雖然不報錯了,但為什麼 我在 insert 時,外掛程式代碼沒有執行呢???
我們刪除 javaue,然後重建一下:
再次啟動 start javaue —— 記住我的ID,再不成功,我直播倒立寫代碼 ~
結果我又失望了:外掛程式似乎沒有執行 —— 外掛程式的代碼會產生一個 D:\ SampleHandler.log 的記錄檔的,但結果沒有。
我似乎又打臉了 —— 啪啪的疼~
我整個人都不好了,日子本已如此艱難,真心快要過不下去了。
就在我一籌莫展時,我有事沒事的 翻看 \x86ogg4oracletarget\ 的幾個 6個字母的 檔案夾。
意外發現了一個檔案,我好奇的將檔案開啟。
我看到了 一個路徑:沒錯啊!就是我配置的 資料檔案夾 路徑。
確實沒錯啊!難道非要驗證一下 路徑嗎?我雖然吃路徑的虧 上了 5次當了。
—— 但這個路徑確實沒錯啊,還不信,我複製給你看看。
整個人都不好了,文本配置最大的弊端就是:你敲幾百幾千個字母,一點手誤都不能有(尼瑪路徑錯了還沒提示)
再次重建 javaue,插入資料 —— 我這次也沒抱啥希望了,被折磨哭了都,不想被打臉了。
我看到了 一個 路徑: \dirdat\r1000000 —— 感覺很奇怪:
源端 ext1 >>> 目標端 rep1,這種資料檔案 都已經到了 r1000005 了 —— 為什麼 javaue 還在找 r1000000
—— 要不,在源端 重建一個 ext2,使用 r2,讓 javaue 從 r2 找資料?
開啟源端 OGG 目錄:建立 ext2
源端 添加、啟動 ext2,啟動成功(我都已經駕輕就熟了) :
開啟目標端,重建 javaue,使用 r2:
這次,我們看到了一段之前沒有出現過的代碼:
開啟 dirdat 目錄:
再次執行 insert 指令碼,插入資料的那一刻,javaue 崩潰了:
一臉懵逼,整個人都不好了。 就在我手足無措時,我意外看到 D:\ SampleHandler.log 檔案被建立了 —— 雖然程式崩潰了,但是Java代碼執行了。
FlagFile 意外配置成功了(本文不多說了,就截了個圖)
心累了,又折騰了一天時間。直接說結果吧:
OGG Adapter Java,只和 /dirdat/r2000000 這種資料有關【和 版本無關、和 x86 x64 無關,和 源端、目標端 無關。】
整個OGG 所有涉及到的所有路徑,都必須使用 反斜線 /。【如果寫成 D:\AAA\x86\ 程式可能會識別為亂碼而詭異崩潰。】
尤其注意:添加 javaue 時,路徑一定要用 反斜線 /
其實直到現在,
OGG Adapter Java 11 x86 版本 每次都會崩潰。就是前兩個步驟的BUG:資料變化捕獲到了,Java代碼執行了,但是程式崩潰了。
OGG Adapter Java 12 x64 版本,我把 /dirprm/javaue.prm 和 /dirprm/javaue.properties 和 /dirprm/source.def 三個檔案 從 11 拷貝到 12, 執行 add extract javaue —— 程式卻能正常運行,捕獲到資料。
OGG 源端 必須和 Oracle 版本、32\64 位元保持一致。
但是 OGG Adapter 沒那麼多限制。OGG Adapter 只針對 /dirdat/r1 或 /dirdat/r2 這類 Trail 檔案。
最終方案如下:
仔細看 右下角: 我增加了一個 OGG 12 x64 —— 由這個 OGG 啟動 javaue。
而 javaue 只只要對接 磁碟檔案 dirdat\r2000001
雖然 有兩個 OGG 11 x86,但是 好在 磁碟 Trail檔案 是互連的。
放一個成功啟動並執行:
我寫了一個 C#程式,每隔一秒 就向 ADMIN.TB_TEST 寫入一行記錄。
理論上 ROOT.TB_TEST 會同步這些資料。
理論上 javaue 能捕獲到 資料變化。
至此,第二目標完成。
最後放出 最終成功的配置:
或者參見 下一篇文章 《OGG Adapter Java一次性成功》
dirprm 檔案夾:
javaue.prm 配置:
javaue.properties 配置:
Source.def 是產生的(產生方式看文章前面),手寫無效:
custom.jar 是編譯後 匯出的 jar包:
//---------------------------------------------------------------------------------------package sample;import java.io.*;import java.util.ArrayList;import java.util.List;import java.util.Set;//這是 OGG 11 的 import //import com.goldengate.atg.datasource.AbstractHandler;//import com.goldengate.atg.datasource.DsConfiguration;//import com.goldengate.atg.datasource.DsEvent;//import com.goldengate.atg.datasource.GGDataSource.Status;//import com.goldengate.atg.datasource.handler.*;//import com.goldengate.atg.datasource.meta.DsMetaData;//import com.goldengate.atg.datasource.test.DsTestUtils.Logger;//import com.goldengate.atg.datasource.meta.*;//import com.goldengate.atg.datasource.*;//這是 OGG 12 的 import import org.slf4j.Logger;import org.slf4j.LoggerFactory;import oracle.goldengate.datasource.AbstractHandler;import oracle.goldengate.datasource.DsColumn;import oracle.goldengate.datasource.DsConfiguration;import oracle.goldengate.datasource.DsEvent;import oracle.goldengate.datasource.DsOperation;import oracle.goldengate.datasource.DsOperation.OpType;import oracle.goldengate.datasource.DsTransaction;import oracle.goldengate.datasource.GGTranID;import oracle.goldengate.datasource.meta.ColumnMetaData;import oracle.goldengate.datasource.meta.DsMetaData;import oracle.goldengate.datasource.meta.TableMetaData;import oracle.goldengate.datasource.meta.TableName;import oracle.goldengate.datasource.GGDataSource.Status;public class SampleHandler extends AbstractHandler { //OGG 11 和 OGG 12 的 日誌好像不一樣, OGG 12 似乎要寫 LoggerFactory.getLogger(SampleHandler.class); //private final Logger logger = Log4jLogger.getLogger(SampleHandler.class); private final Logger logger = LoggerFactory.getLogger(SampleHandler.class); @Override public void init(DsConfiguration conf, DsMetaData metaData) { super.init(conf, metaData); logger.info("init!"); WriteStringToFile("D:\\SampleHandler.log", "SampleHandler.init(*)"); } @Override public Status transactionCommit(DsEvent e, DsTransaction tx) {// DsMetaData meta = e.getMetaData();// //System.out.println(meta);// // Set<TableName> tableNames = meta.getTableNames();// for(TableName tableName : tableNames){// String tableStr = "";// tableStr = tableStr + tableName+" : ";//// TableMetaData metaData = meta.getTableMetaData(tableName);// ArrayList<ColumnMetaData> columns = metaData.getColumnMetaData();// for(ColumnMetaData column : columns){ // tableStr = tableStr + "\r\n " + column.getColumnName() + " | "+column.getDataType().toString();// }// // System.out.println(tableStr+"\r\n"); // //System.out.println(metaData);// }// // //GGTranID tranId = e.getTargetCheckpointInfo();// //System.out.println(tranId);// // System.out.println(tx.getSize());// System.out.println(tx.getTotalOps());// System.out.println(tx.getReadTime());// System.out.println(tx.getTransactionBeginTime());// // // Object eventSource = e.getEventSource();// System.out.println(eventSource);// // DsOperation lastOp = tx.getLastOperation();// System.out.println(lastOp);// // // List<DsOperation> listOp = tx.getOperations();// System.out.println(listOp.size());// //System.out.println(listOp.get(0).getColumn(0).getBeforeValue());// for(DsOperation op : listOp){// System.out.println(op.getTableName());// } Status superResult = super.transactionCommit(e, tx); logger.info("transactionCommit!"); WriteStringToFile("D:\\SampleHandler.log", "SampleHandler.transactionCommit(*) => "+superResult); return superResult; } @Override public Status operationAdded(DsEvent e, DsTransaction tx, DsOperation dsOperation) { DsMetaData meta = e.getMetaData(); //System.out.println(meta);// Set<TableName> tableNames = meta.getTableNames();// for(TableName tableName : tableNames){// String tableStr = "";// tableStr = tableStr + tableName+" : ";//// TableMetaData metaData = meta.getTableMetaData(tableName);// ArrayList<ColumnMetaData> columns = metaData.getColumnMetaData();// for(ColumnMetaData column : columns){ // tableStr = tableStr + "\r\n " + column.getColumnName() + " | "+column.getDataType().toString();// }// // System.out.println(tableStr+"\r\n"); // //System.out.println(metaData);// } System.out.println("---------------------------------------"); OpType opType = dsOperation.getOperationType(); System.out.println(opType); TableName tableName = dsOperation.getTableName(); System.out.println(tableName.getFullName()); TableMetaData metaData = meta.getTableMetaData(tableName); ArrayList<ColumnMetaData> columnMetas = metaData.getColumnMetaData(); List<DsColumn> columns = dsOperation.getColumns(); for(int i=0; i<columnMetas.size(); i++){ ColumnMetaData columnMeta = columnMetas.get(i); DsColumn column = columns.get(i); System.out.println(" " + columnMeta.getColumnName() + "\t | \t"+ column.getAfterValue() + (column.isChanged()? "\t >>> \t" +column.getAfterValue():"")); } System.out.println("---------------------------------------"); Status superResult = super.operationAdded(e, tx, dsOperation); logger.info("operationAdded!"); WriteStringToFile("D:\\SampleHandler.log", "SampleHandler.operationAdded(*) => "+superResult); return superResult; } //@Override //public DataSourceListener.State getState() { // return super.getState(); //} @Override public void destroy() { super.destroy(); WriteStringToFile("D:\\SampleHandler.log", "SampleHandler.destroy(*)"); logger.info("destroy!"); } @Override public String reportStatus() { String superResult = "OK"; //super.reportStatus(); 調用父類函數,程式就會崩潰。 WriteStringToFile("D:\\SampleHandler.log", "SampleHandler.reportStatus(*) => "+superResult); return superResult; //return "status report...==="; } public static void WriteStringToFile(String filePath, String text) { try { System.out.println("AAAAAAAAAAAAAAAAA :" + text); FileWriter writer = new FileWriter(filePath, true); writer.write("\r\n"+text); writer.close(); } catch (IOException e) { //e.printStackTrace(); System.out.println(e.getMessage()); } } }//---------------------------------------------------------------------------------------
至此,OGG 兩大目標 全部完成。幾乎把能踩的坑都踩了一遍。
雖然,我會再寫一篇文章 《OGG Adapter Java一次性成功》
—— 但是,不要想太多:你還是得乖乖的回到 這篇文章,學習如何從坑中逃出來。
—— 此篇OGG踩坑文章,踩的各種坑 不下十幾種,從配置到代碼、從編碼格式到反斜線,從版本到位元,從環境變數到筆誤。
—— 作者著實不容易。
最後還是以一首打油詩結尾:現代詩:《OGG的迷惘》
那一刻,
晶瑩的淚水滑過臉龐,
我似乎,
看到了成功的希望。
蹉跎與掙紮,
糾結與迷惘。
在折騰中,我終究能走向想要的遠方。
—— 再給我一次機會,讓我再配置一次OGG。
—— 不!我選擇 死亡(罵娘)~
打油詩:《神坑OGG》
神坑最多OGG,
坑得勞資沒脾氣。
坑得勞資沒脾氣~
神坑最多OGG~
兩首詩把 OGG 批了一頓,還能怎樣呢?當然是選擇 原諒他啊。
舒小龍 2018-05-31 20:02
『OGG 02』Win7 配置 Oracle GoldenGate Adapter Java 踩坑指南