『OGG 02』Win7 配置 Oracle GoldenGate Adapter Java 踩坑指南


上一文章 《__Win7 配置OGG(Oracle GoldenGate).docx》定下了 兩個目標:

  • 目標1:

給安裝的Oracle_11g 創建 兩個用戶 admin 和 root 。

admin 對應了 ADMIN 結構,創建了一個 TB_ TEST表。

root 對應了 ROOT 結構,也創建一個 TB_ TEST (表結構一摸一樣)。

當 admin.TBTEST 中的表數據 變化時,root.TB TEST 的表數據 自動同步(備份)

PS. 實際的 容災備份,肯定是 兩個 Oracle 服務器,通過網絡傳輸 備份數據 —— 各位可以想象 admin 和 root 在兩台不同服務器 上。

  • 目標2:

當 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.properties
import 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:

窗口再次一閃而過,啟動失敗,繼續查錯。

參考:https://blog.csdn.net/catoop/article/details/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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM