目录

目录

前言

 运行

TableInput描述

 TableOutput描述

调试代码


前言

        在之前我写了如何通过java 脚本来修改数据,从而确定有一个processRow()方法,该方法中能获取到数据信息等,那么接下来就是需要运行一个简单的表交换来看数据是怎么流的。

        首先写一个简单的tableInput->tableOutput的交换,这里代码就贴在最后,毕竟只是用mysql表交换,数据也不多,太简单了。

        定义一个源表,放两条数据,然后新建一个user_info_dest目标表,结构和源表相同,但注意不要给主键(这样可以多次交换而不用删除dest表数据)

kettle javascript怎么获取 表输入 中的数据 kettle 获取表结构_kettle

 运行

         首先在TableInput和TableOutput的构造方法、init()、processRow()、doQuery()、writeToTable()、dispose()等方法打上断点,以便debug后能看到数据流向。

         准备了两条数据,在TableInput类中,processRow()方法总共进入了三次,

        首先是第一次      构造函数-->init()-->processRow()-->doQuery()-->processRow()-->putRow() 

        这里写了两个processRow,后一个是表明走完doQuery()方法后又回到processRow()。

        第二次  processRow()

        第三次 processRow()  --> dispose()

        这样在TableInput中就走完表输入,此时将TableInput中的断点去掉,这样第二次运行交换才能看到TableOutput类(非必要),因为所有节点是同时启动,然后等待跳内的数据,如果有数据就处理,没有就阻塞。

        TableOutput中方法调用基本同TableInput,也是走了三次processRow()。

TableInput描述

                在如下图的过程中,进入TableInput的构造函数,并不是在初始化TableInputMeta时初始化的。

        

kettle javascript怎么获取 表输入 中的数据 kettle 获取表结构_kettle_02

 

kettle javascript怎么获取 表输入 中的数据 kettle 获取表结构_数据_03

         而TableInputMeta中设置的SQL此时也能看到,如下图所示,

kettle javascript怎么获取 表输入 中的数据 kettle 获取表结构_kettle_04

         

        从下图可以看到TableInput中查询数据库,然后把数据保存在data.rs中,那么rs中就能看到表数据了,rs就是一个ResultSet,

kettle javascript怎么获取 表输入 中的数据 kettle 获取表结构_数据_05

         如下图所示,rowMeta保存字段信息,

kettle javascript怎么获取 表输入 中的数据 kettle 获取表结构_kettle_06

         所以可以知道data.rs保存了数据,data.rowMeta保存了列信息。

        如下图就知道能从data.rs中获取到第一条数据,data.thisrow就保存了本次processRow的数据,data.nextrow就保存了下一次进入processRow需要插入的数据。

kettle javascript怎么获取 表输入 中的数据 kettle 获取表结构_kettle_07

         如下图,在putRow以后,下一次需要插入的数据就赋值给了data.thisrow。

kettle javascript怎么获取 表输入 中的数据 kettle 获取表结构_pdi_08

         从下图可以看出,这个processRow方法是被循环调用的,由一个step的标志位去控制是否跳出循环。

 

kettle javascript怎么获取 表输入 中的数据 kettle 获取表结构_kettle_09

        当第二次进入processRow时,如下图,获取下一次的数据,但没有数据了,所以data.nextrow为空,所以在putRow方法后,data.thisrow就是空。

putRow( data.rowMeta, data.thisrow ); // fill the rowset(s). (wait for empty)
            data.thisrow = data.nextrow;

kettle javascript怎么获取 表输入 中的数据 kettle 获取表结构_数据_10

         当第二条数据插入完成,第三次进入processRow方法时,此时data.thisrow为空,也意味着此时该结束此步骤了。

kettle javascript怎么获取 表输入 中的数据 kettle 获取表结构_pdi_11

        控制台打印日志如下, 看tableOutput和tableInput的时间,也可以看出两个类是异步的,不是说上一个初始化完成了下一个才初始化。        

kettle javascript怎么获取 表输入 中的数据 kettle 获取表结构_pdi_12

 TableOutput描述

        此处就跳过和TableInput相似的断点描述了,如下图writeToTable方法,这里能看出Object[] r保存了数据,而且是一行数据,并不是所有查询到的数据,这也证明有多少条数据就进入多少次processRow。

        rowMeta依旧保存了列的信息。

kettle javascript怎么获取 表输入 中的数据 kettle 获取表结构_kettle_13

         如下图,insertStatement是空的,第一次Map中肯定没有,所以需要获取,获取完放入Map中,就是一个缓存,这样能加快速度。

public Map<String, PreparedStatement> preparedStatements;

 

kettle javascript怎么获取 表输入 中的数据 kettle 获取表结构_etl_14

         如下图所示生成insert的SQL语句,那么猜测就是通过insert语句插入咯,万变不离其宗。

kettle javascript怎么获取 表输入 中的数据 kettle 获取表结构_mysql_15

 如下图  setValue用来往insertStatement中的?,?设置值,insertRow就是用来insertStatement.executeUpdate()方法。

有兴趣可以自己看下setValues和insertRow方法的代码。

kettle javascript怎么获取 表输入 中的数据 kettle 获取表结构_mysql_16


        所以从上面调试可以看出,其实也就是先通过select语句来将数据保存在ResultSet对象中,然后通过insert语句将数据插入,这不就是平常的JDBC么!!!

        这样想是不是发现其实这个kettle源码也没什么嘛,万变不离其宗,是不是信心大涨。

kettle javascript怎么获取 表输入 中的数据 kettle 获取表结构_mysql_17

调试代码

package com.lw.kettle;

import com.sun.org.apache.xerces.internal.impl.xpath.XPath;
import org.junit.Before;
import org.junit.Test;
import org.pentaho.di.core.KettleEnvironment;
import org.pentaho.di.core.database.DatabaseMeta;
import org.pentaho.di.core.exception.KettleException;
import org.pentaho.di.core.plugins.PluginRegistry;
import org.pentaho.di.core.plugins.StepPluginType;
import org.pentaho.di.core.util.EnvUtil;
import org.pentaho.di.trans.Trans;
import org.pentaho.di.trans.TransHopMeta;
import org.pentaho.di.trans.TransMeta;
import org.pentaho.di.trans.step.StepMeta;
import org.pentaho.di.trans.step.StepMetaInterface;
import org.pentaho.di.trans.steps.tableinput.TableInputMeta;
import org.pentaho.di.trans.steps.tableoutput.TableOutputMeta;

/**
 * @author lw
 * @date 2021/11/24 0024
 * @description
 */
public class ExchangeWithExpandCode {

    @Before
    public void before() {
        try {
            // 初始化Kettle环境
            KettleEnvironment.init();
            EnvUtil.environmentInit();
        } catch (KettleException e) {
            e.printStackTrace();
        }
    }

    @Test
    public void exchange()throws KettleException{
        TransMeta transMeta = new TransMeta();
        transMeta.setName("交换");

        PluginRegistry registry = PluginRegistry.getInstance();

        StepMeta inputStep = getTableInputStep(transMeta,registry);
        StepMeta outputStep = getTableOutputStep(transMeta,registry);

        Trans trans = new Trans(transMeta);

        transMeta.addTransHop(new TransHopMeta(inputStep, outputStep));

		//执行转换
		trans.execute(null);

		//等待完成
		trans.waitUntilFinished();
		if (trans.getErrors() > 0) {
			System.out.println("交换出错.");
			return;
		}
    }


    /**
     * 获取表输入
     * @param transMeta
     * @param registry
     * @return
     */
    public StepMeta getTableInputStep(TransMeta transMeta,PluginRegistry registry) throws KettleException{
        /*
		1. 源数据库连接
		 */
        String mysql_src = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" +
                "<connection>" +
                "<name>mysql_src</name>" +
                "<server>192.168.10.64</server>" +
                "<type>MySQL</type>" +
                "<access>Native</access>" +
                "<database>test</database>" +
                "<port>3306</port>" +
                "<username>root</username>" +
                "<password>root</password>" +
                "</connection>";

        DatabaseMeta srcDatabaseMeta = new DatabaseMeta(mysql_src);

        transMeta.addDatabase(srcDatabaseMeta);

        TableInputMeta tableInputMeta = new TableInputMeta();
        String tableInputPluginId = registry.getPluginId(StepPluginType.class,
                tableInputMeta);

        tableInputMeta.setDatabaseMeta(srcDatabaseMeta);
        //设置查询条件
        String selectSql = "select id ,name from user_info_src";
        tableInputMeta.setSQL(selectSql);

        StepMeta tableInputStep = new StepMeta(tableInputPluginId,
                "tableInput", (StepMetaInterface) tableInputMeta);

        //给步骤添加在spoon工具中的显示位置
        tableInputStep.setDraw(true);
        tableInputStep.setLocation(100, 100);

        transMeta.addStep(tableInputStep);

        return tableInputStep;
    }

    /**
     * 表输出
     * @param transMeta
     * @param registry
     * @return
     * @throws KettleException
     */
    public StepMeta getTableOutputStep(TransMeta transMeta,PluginRegistry registry) throws KettleException{
        String mysql_dest = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" +
                "<connection>" +
                "<name>mysql_dest</name>" +
                "<server>192.168.10.64</server>" +
                "<type>MySQL</type>" +
                "<access>Native</access>" +
                "<database>test</database>" +
                "<port>3306</port>" +
                "<username>root</username>" +
                "<password>root</password>" +
                "</connection>";
        DatabaseMeta destDatabaseMeta = new DatabaseMeta(mysql_dest);

        TableOutputMeta tableOutputMeta = new TableOutputMeta();
        tableOutputMeta.setDatabaseMeta(destDatabaseMeta);

        tableOutputMeta.setSchemaName(null);
        tableOutputMeta.setTablename("user_info_dest");

        String tableOutputPluginId = registry.getPluginId(StepPluginType.class, tableOutputMeta);
        StepMeta tableOutputStep = new StepMeta(tableOutputPluginId, "tableOutput", (StepMetaInterface) tableOutputMeta);

        //将步骤添加进去
        transMeta.addStep(tableOutputStep);

        //给步骤添加在spoon工具中的显示位置
        tableOutputStep.setDraw(true);
        tableOutputStep.setLocation(200, 200);

        return tableOutputStep;
    }
}