加精

不一定要用kettle做数据迁移 - JFinal在数据操作中有奇效!

  • • 发表于2018-07-22 04:46:33.0
  • • 作者 小徐同学
  • • 596 次浏览
  • • 2 条评论
  • • 最后编辑时间 2018-11-29 10:42:41.0
  • • 来自 [JFinal]

原创声明:本文为作者原创,未经允许不得转载,经授权转载需注明作者和出处

个人认为,数据迁移大概三个步骤:数据整理、数据清洗、数据验证。其中最主要的,还是数据整理,这包括数据源表数据梳理,字段对接、关联关系匹配…等等,而且,还需要对业务有一定了解。我在联想项目组负责数据迁移,一开始用的是kettle。个人觉得,无论用什么工具,前置工作一定要把sql写出来先,kettle也不例外。但是对于我个人而言(纯kettle小白):
需要投入比较多的精力才能学好;
对一些关联关系、字段转换处理特别麻烦;
性能不咋滴(至少没下面介绍的好);
对逻辑思维要求比较高;
开发效率低。

闲话少说,我自己用的数据迁移其实就是写代码!没错,自己写代码!试想一下,当处理关系特别复杂的数据的时候,比如树形结构数据、地址数据匹配、父子结构数据、一些批量数据修改等等动作,当你用kettle处理的时候,你可能在脑海中已经有了处理步骤的方案,却很难快速在kettle中体现。
我在写代码中,用了JFinal 的 dao 组件。得益JFInal ActiveRecordPlugin可以独立于java web 环境运行在任何普通的java程序中,所以一个迁移动作,就是一个main方法。

举个栗子:

public static void main(String args) {
    MemberStartDb.startMysql();
    kocdeImport();
}

public static void kocdeImport() {
    List<Record> list = Db.find(Db.getSql("member.getKcode"));
    Db.batchSave("mc_member_kcode", list, 1000);
}

sql如下:

#sql("getKcode")
    SELECT
        a.jsxno as member_code,
        a.fxsno as seller_code,
        productgroupno as product_group_code,
        a.`status` as audit_status,
        a.lresellerno as kcode, 
        a.createdate as create_time,
        a.updatedate as update_time,
        b.jxsname as member_company_name,
        c.fxsname as seller_company_name,
        'import' as create_person
    FROM
        d_jxs_fxs_relation a
      LEFT JOIN d_jxsinfo b ON a.jsxno = b.jxsno
        LEFT JOIN d_fxsinfo c ON a.fxsno = c.fxsno 
        inner join hs_account h on a.jsxno = h.jxs_num and h.is_login = 0 and h.is_active = 0 and h.login_name = h.master_login_name
    where 1 = 1
    ORDER BY
        jxsname,
        a.createdate 
#end

是不是很简单捏,我只需要把sql整理好,剩下的就是几行代码的事了。

下面介绍下整个过程以及一些特性:

1.连接数据库:

    public static void startMysql() {
        //jdbc url
        String url = "jdbc:mysql://localhost:3306/test?characterEncoding=utf-8&zeroDateTimeBehavior=convertToNull";
        //druid连接池
        DruidPlugin druidPlugin = new DruidPlugin(url, "yunxi", "Hz_5mu8Uz+");
        ActiveRecordPlugin arpMysql = new ActiveRecordPlugin(druidPlugin);
        //是否打印sql
        arpMysql.setShowSql(true);
        //设置方言 这里是mysql,也支持sqlserver oracle psgSql
        arpMysql.setDialect(new MysqlDialect());
        //这个类似mybaticsSql,动态sql管理,但是比前者好用N倍(个人感觉,不喜勿喷)
        arpMysql.setBaseSqlTemplatePath(PathKit.getRootClassPath() + "/sql");
        arpMysql.addSqlTemplate("import.sql");
        arpMysql.getSqlKit().getEngine().addSharedObject("sk", new com.jfinal.kit.StrKit());

        //启动插件
        druidPlugin.start();
        arpMysql.start();
        //缓存插件
        new EhCachePlugin().start();

    }

有同学会问,多数据源怎么办,没关系,复制多一个方法就好了,只要初始化ActiveRecordPlugin的时候指定数据源名称,如下。
ActiveRecordPlugin arpMysql = new ActiveRecordPlugin(“db2”,druidPlugin);

用的话根据先手启动顺序,第一个默认 Db.find()… 其他的就是Db.use(“db2”).find….,当然如果你要跨库连表查询也可以,只要保证在一个连接内,就可以。比如:

Db.find("select * from table1 a left join db2.table2 b on a.id  = b.xx ");

另外JFinal 提供了Ehcache缓存插件,也就意味如果我们在数据迁移,要做很多重复查询动作,可以用这样用:

        //sql语句缓存
        Db.findByCache("cachename","key","select * from table");
        Db.findFirstByCache("cachename","key","select * from table limit 1");
        //扩展缓存,随便你想存什么
        CacheKit.put("cacheName","key",new Object());
        CacheKit.get("cacheName","key");

数据库连接启动后,就可以使用Db类各种操作sql了。如下:
不详细介绍了,有兴趣可以看看源码,重点是保存 时候,一定要跟目标表字段保持一致,

 Db.find(sql);
 Db.update(sql);
 Db.save("tablename",new Record());
 Db.save("tablle","primaryKey",new Record();
 Db.batchSave...
 Db.query...
 List<Record> records = Db.find("select id,name,interest from t1");
        for (Record re: records) {
            String interest = re.getStr("interest");
            if("篮球".equals(interest)){
                re.set("interest_type",1);
            }else if("足球".equals(interest)){
                re.set("interest_type",2);
            }else{
                re.set("interest_type",3);
            }
            //要去掉id,interest字段,不然报错
            re.remove("id","interest");

            //t2表只有id(自增),name,interest_type
            Db.save("interest_type",re);
        }

甚至你可以使用事务,如果操作失败,就回滚:

 boolean tx = Db.tx(new IAtom() {
            @Override
            public boolean run() throws SQLException {
                for (Record re : records) {
                    String interest = re.getStr("interest");
                    if ("篮球".equals(interest)) {
                        re.set("interest_type", 1);
                    } else if ("足球".equals(interest)) {
                        re.set("interest_type", 2);
                    } else {
                        re.set("interest_type", 3);
                    }
                    //要去掉id,interest字段,不然报错
                    re.remove("id", "interest");

                    //t2表只有id(自增),name,interest_type
                    Db.save("interest_type", re);
                }
                ;
                //return false 为失败 sql执行中抛出异常也回滚
                return true;
            }
        });

引用的jar

<!-- JFinal -->
<dependency>
    <groupId>com.jfinal</groupId>
    <artifactId>jfinal</artifactId>
    <version>3.4</version>
</dependency>

最后:说的不是很仔细,但是思想到位了,有兴趣的可以一起交流交流。有问题什么可以留言,或者叮叮找我,本人JFinal爱好者,有喜欢的小伙伴可以一起讨论。

评论区(共2条评论)
小徐同学
小徐同学 2018-08-25 04:36

ddd

Mr.s Zh
Mr.s Zh 2019-01-21 13:44

挺好的

2条评论
Ctrl+Enter
作者

Michael

小徐同学

帖子:34 回复:0

全栈搬运工

作者详情》
Top