• 『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 FilesJavajdk1.8.0121 和 C:Program Files (x86)Javajdk1.8.0121。

    • 我后悔自己的OGG目录 取了这么长的 一个名字: D:oracleproduct11.1.0x86_ogg4oracle

    • 接下来的文章:这些坑将导致各种诡异的问题 —— 填坑指南,作者带着你 一起踩坑一起填,在失败中积累厚重经验、在填坑中收获绝对稳定。

    配置环境变量:

    我的电脑 64位Win7,安装了 64位、32位 位两种 JDK。Oracle_11g 32位,OGG 32位。

    进行如下操作:

    • 找到 64位 JDK目录 —— 右键,“360强力删除” —— 没错,强力粉碎,这源自我踩坑踩出的仇恨,粉碎,粉碎。 桌面>计算机>右键>属性>高级系统设置>“高级”选项卡>环境变量。

    CLASSPATH : .;%JAVAHOME%lib ools.jar;%JAVAHOME%libdt.jar;%JAVA_HOME%in;

    JAVAHOME : C:Program Files (x86)Javajdk1.8.0121

    JREHOME : C:Program Files (x86)Javajre1.8.0121

    Path : %JAVA_HOME%in;

    验证环境变量:

    打开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:oracleproduct11.1.0x86ogg4oracletarget 【目标端】双击运行 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:oracleproduct11.1.0x86_ogg4oracle_targetdirprmjavaue.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 窗口),重新打开 x86ogg4oralcetargetggsci.exe 输入命令: start mgr start javaue

    现代诗:《OGG的迷惘》

    那一刻,

    晶莹的泪水滑过脸庞,

    我似乎,

    看到了成功的希望。

    蹉跎与挣扎,

    纠结与迷惘。

    在折腾中,我终究能走向想要的远方。

    —— 再给我一次机会,让我再配置一次OGG。

    —— 不!我选择 死亡(骂娘)~

    打油诗:《神坑OGG》

    神坑最多OGG,

    坑得劳资没脾气。

    坑得劳资没脾气~

    神坑最多OGG~

    开始测试 javaue 插件是否成功:

    程序这次崩溃了,对比一下 两种配置:

    在下面的配置(崩溃)中,我们看到了一个路径 dirlib/custom.jar。

    我们尝试将 eclipse 导出的 jar 文件 D:Tempcustom.jar,复制到 x86ogg4oracletargetdirlib 文件夹(dirlib 要手动创建)

    再次运行,还是崩溃,还是相同的错误信息:

    虽然不报错了,但为什么 我在 insert 时,插件代码没有执行呢???

    我们删除 javaue,然后重建一下:

    再次启动 start javaue —— 记住我的ID,再不成功,我直播倒立写代码 ~

    结果我又失望了:插件似乎没有执行 —— 插件的代码会生成一个 D: SampleHandler.log 的日志文件的,但结果没有。

    我似乎又打脸了 —— 啪啪的疼~

    我整个人都不好了,日子本已如此艰难,真心快要过不下去了。

     

    就在我一筹莫展时,我有事没事的 翻看 x86ogg4oracletarget 的几个 6个字母的 文件夹。

    意外发现了一个文件,我好奇的将文件打开。

    我看到了 一个路径:没错啊!就是我配置的 数据文件夹 路径。

    确实没错啊!难道非要验证一下 路径么?我虽然吃路径的亏 上了 5次当了。

    —— 但这个路径确实没错啊,还不信,我复制给你看看。

    整个人都不好了,文本配置最大的弊端就是:你敲几百几千个字母,一点手误都不能有(尼玛路径错了还没提示)

     

    再次重建 javaue,插入数据 —— 我这次也没抱啥希望了,被折磨哭了都,不想被打脸了。

    我看到了 一个 路径: dirdat 1000000 —— 感觉很奇怪:

    源端 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:AAAx86 程序可能会识别为乱码而诡异崩溃。】

    尤其注意:添加 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 版本、3264 位保持一致。

    但是 OGG Adapter 没那么多限制。OGG Adapter 只针对 /dirdat/r1 或 /dirdat/r2 这类 Trail 文件。

    最终方案如下:

    仔细看 右下角: 我增加了一个 OGG 12 x64 —— 由这个 OGG 启动 javaue。

    而 javaue 只只要对接 磁盘文件 dirdat 2000001

    虽然 有两个 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 + "
       " + column.getColumnName() + " | "+column.getDataType().toString();
    //          }
    //          
    //          System.out.println(tableStr+"
    ");            
    //          //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 + "
       " + column.getColumnName() + " | "+column.getDataType().toString();
    //          }
    //          
    //          System.out.println(tableStr+"
    ");            
    //          //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() + "	 | 	"+ column.getAfterValue() + (column.isChanged()? "	 >>> 	" +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("
    "+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

  • 相关阅读:
    C#事件由浅至深简析
    数据传递型情景下事件机制与消息机制的架构设计剖析(目录)
    数据传递型情景下事件机制与消息机制的架构设计剖析(一)
    从问题说开来……
    windows server作为文件服务器如何精细控制权限
    TortoiseGit 删除密码 清除密码 让你每次都输入账号密码提交
    adb基础常用命令总结
    python之冒泡排序
    python水仙花数
    fiddler抓取手机(iPhoneX)APP上HTTPS接口数据
  • 原文地址:https://www.cnblogs.com/shuxiaolong/p/Win7_OGG_Javaue_Fail.html
Copyright © 2020-2023  润新知