数据库表同步的三种方法

1、前言:

最近项目准备上线,要先做一下并行,所以要把调用接口的请求 请求到生产环境的同时也请求到并行环境。我刚开始,写了一个程序,多线程去生产数据库(接口有记录表,记录请求报文)取到请求报文,然后再拼接成curl请求命令,请求到并行环境,结果跑了没半天就差点儿把生产数据库搞挂。原因是,我的程序每五分钟调用一次,调用会获取11个数据库连接,结果因为生产上数据量大,五分钟没有处理完成,另一个调度就调起来了,这样一下午累积下来,产生了上百个连接,生成cpu飙到了%90以上,触发了告警,领导收到了告警短信才发现了问题。
之后应领导要求,我的并行程序不能直接连接生产库,需要异步处理(需要数据库做中转),那么就涉及到一个如何获取生产数据库中的报文数据的问题。通过上网查询,大体有三个方案:

1.1 使用触发器

在接口报文记录表上添加一个触发器,每次请求的报文插入生产记录表的同时触发器插入到中转数据库。
优点:编程简单,只需要几行
缺点:会影响生产数据库性能,同时该触发器需要配合dblink,可能存在潜在危险。

-- 一个简单的oracle触发器
CREATE OR REPLACE TRIGGER MY_TGR
BEFORE INSERT ON jd.ims_json_soap_1_0
FOR EACH ROW--对表的每一行触发器执行一次,插入test_b的同时插入test_a
BEGIN
insert into cd.ims_json_soap_1_0(name,age,school,home,ext)  values(:NEW.name,:NEW.age,:NEW.school,:NEW.home,:NEW.ext);
END;
1.2 使用canal

canal是阿里巴巴提供的一个开源工具,通过监听数据库binlog日志,解析出语句,然后执行,该程序对于mysql很友好,但是oracle(归档日志)貌似支持部分.太新的版本应该还不支持,这个还没有尝试。

1.3 使用kettle

kettle是一款国外的开源ETL工具,使用的时候只需要下载解压就可以使用,数据抽取速度可以达到每秒上万条数据的同步。

2、kettle的使用

2.1 下载安装kettle

我这里使用的是pdi-ce-7.1.0.0-12
数据库表同步的三种方法_第1张图片

2.2 表同步生成ktr文件

因为生产数据是实时有调用记录插入的,所以我的同步方案是增量同步。
通过目标表的最新时间到生产源表里面获取最新的记录

2.2.1 最终转换效果

数据库表同步的三种方法_第2张图片

2.2.2 MaxDate

获取目标表(中转数据库中的表)最大时间做为一个表输入。
数据库表同步的三种方法_第3张图片

2.2.3 常规(生产数据库)

注意下面的从步骤插入数据,sql语句中的问号会在执行的时候替换为下面的MaxData(该名字需要和上一步中的步骤名称保持一致)
数据库表同步的三种方法_第4张图片

2.2.4 表输出

这里其实还可以使用 插入/更新 但是这种方式相对慢一些,但是更灵活,可以自定义同步的字段,由于我这里表结构都是相同的,所以我采用表输出的方式,这样的效率更高。

数据库表同步的三种方法_第5张图片

数据库表同步的三种方法_第6张图片
最后按住shirt通过拖拉将两个输入和一个输出连接起来就可以了
数据库表同步的三种方法_第7张图片
我这里应为分表的关系有十张分表都需要同步,所以我复制了十个这样的转换。

2.3 执行ktr文件

数据库表同步的三种方法_第8张图片
转换过程
数据库表同步的三种方法_第9张图片

3、java整合kettle,通过程序调用执行ktr文件

由于我的需要放在服务器上去定时调度,所以我采用的是Java + crontab的方式实现的定时调度执行ktr文件。

   /**
     * 执行ktr文件
     * @param args
     */
    public static void main(String[] args) throws KettleException {
        //初始化ketlle
        KettleEnvironment.init();
        //创建转换元数据对象
        //TransMeta meta = new TransMeta("etl/update_insert_Trans.ktr");
        TransMeta meta = new TransMeta("D:\\Tools\\Kettle\\save\\常规到紧急0分表.ktr");
        Trans trans = new Trans(meta);
        trans.prepareExecution(null);
        trans.startThreads();
        // 等待执行完成
        trans.waitUntilFinished();
        if(trans.getErrors()!=0){
            System.out.println("执行失败!");
        }
    }

你可能感兴趣的:(sql,java)