kettle调试查看源码数据
目录
目录
前言
在之前我写了如何通过java 脚本来修改数据,从而确定有一个processRow()方法,该方法中能获取到数据信息等,那么接下来就是需要运行一个简单的表交换来看数据是怎么流的。
首先写一个简单的tableInput->tableOutput的交换,这里代码就贴在最后,毕竟只是用mysql表交换,数据也不多,太简单了。
定义一个源表,放两条数据,然后新建一个user_info_dest目标表,结构和源表相同,但注意不要给主键(这样可以多次交换而不用删除dest表数据)
运行
首先在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时初始化的。
而TableInputMeta中设置的SQL此时也能看到,如下图所示,
从下图可以看到TableInput中查询数据库,然后把数据保存在data.rs中,那么rs中就能看到表数据了,rs就是一个ResultSet,
如下图所示,rowMeta保存字段信息,
所以可以知道data.rs保存了数据,data.rowMeta保存了列信息。
如下图就知道能从data.rs中获取到第一条数据,data.thisrow就保存了本次processRow的数据,data.nextrow就保存了下一次进入processRow需要插入的数据。
如下图,在putRow以后,下一次需要插入的数据就赋值给了data.thisrow。
从下图可以看出,这个processRow方法是被循环调用的,由一个step的标志位去控制是否跳出循环。
当第二次进入processRow时,如下图,获取下一次的数据,但没有数据了,所以data.nextrow为空,所以在putRow方法后,data.thisrow就是空。
putRow( data.rowMeta, data.thisrow ); // fill the rowset(s). (wait for empty)
data.thisrow = data.nextrow;
当第二条数据插入完成,第三次进入processRow方法时,此时data.thisrow为空,也意味着此时该结束此步骤了。
控制台打印日志如下, 看tableOutput和tableInput的时间,也可以看出两个类是异步的,不是说上一个初始化完成了下一个才初始化。
TableOutput描述
此处就跳过和TableInput相似的断点描述了,如下图writeToTable方法,这里能看出Object[] r保存了数据,而且是一行数据,并不是所有查询到的数据,这也证明有多少条数据就进入多少次processRow。
rowMeta依旧保存了列的信息。
如下图,insertStatement是空的,第一次Map中肯定没有,所以需要获取,获取完放入Map中,就是一个缓存,这样能加快速度。
public Map<String, PreparedStatement> preparedStatements;
如下图所示生成insert的SQL语句,那么猜测就是通过insert语句插入咯,万变不离其宗。
如下图 setValue用来往insertStatement中的?,?设置值,insertRow就是用来insertStatement.executeUpdate()方法。
有兴趣可以自己看下setValues和insertRow方法的代码。
所以从上面调试可以看出,其实也就是先通过select语句来将数据保存在ResultSet对象中,然后通过insert语句将数据插入,这不就是平常的JDBC么!!!
这样想是不是发现其实这个kettle源码也没什么嘛,万变不离其宗,是不是信心大涨。
调试代码
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;
}
}