说明:
- 背景说明:需要定时同步别的业务系统基于webservice发布的数据(主表、附表)
- 问题缘由:service提供方,主表支持批量查询,一次可以查询100条,但是附表只能根据主表的主键一条一条的查询。因此我如果要获取所有的附表内容就要循环访问服务(约1万多次)因此会出现Java:java.lang.OutOfMemoryError: GC overhead limit exceeded
解决方法:
总体思路:出现内存溢出主要是因为我在一个总job中循环了1万多次webservice,在大job中循环调用小job(100次访问)解决问题。
- 总体流程图
- 前两项检查Web服务是否可用,就不具体展示了,可以参考下面的链接,我也是参考他的博客做的https://blog.csdn.net/a275838263/article/details/51302541
- lawCount初始化,执行sql是先清空内容表(我是全量更新),查询主表确定需要循环的次数,把lawCount复制到结果集
- 设定循环变量,lawCount来自前面的结果集,startIndex(从0开始),endIndex(从100开始)确定需要遍历的主键范围
var lawCount=previous_result.getRows();//获取上一个传递的结果 if (lawCount == null && (lawCount.size()) == 0) { false; }else{ parent_job.setVariable("lawCount", lawCount.get(0).getNumber("lawCount",0)); parent_job.setVariable("startIndex", 0); parent_job.setVariable("endIndex", 100); true; }
- 检验startIndex的值,只要startIndex的值<=lawCount,就进入循环,调用服务
- lawID初始化,根据startIndex,endIndex查询循环需要依赖的主键,复制到结果集
- 调用子job,在子job中循环访问webservice,得到数据
- 把上一步查到的记录存到变量中,设定小范围循环变量index,lawSize,以及参数lawID到变量
var lawList=previous_result.getRows();//获取上一个传递的结果 debugger; if (lawList == null &&(lawList.size()==0)) { false; }else{ parent_job.setVariable("lawList", lawList);//ArrayList存储法律法规记录变量,以数组形式保存入law1,law2 parent_job.setVariable("lawSize", lawList.size());//存储法律法规的总数量 parent_job.setVariable("index", 0);//循环控制变量 parent_job.setVariable("lawID",lawList.get(0).getString("LAWID","LAWID")); true; }
- 检验小循环(100个循环)index的值(从0开始),index小于lawSize(100个lawID)就进入循环
- 具体的抽取ktr由于业务需求,附表字段包括主表部分字段,因此我走了两条查询,最后把记录关联插入;
- 生成记录:是为了初始化一个常量参数
- java代码中获取lawID,并配合生成的记录加密后,形成服务访问的验证字符串
- 具体的访问步骤
- 将out用json解析
- 去除out字段
- 关联两个结果集记录
- 插入表格
- 递增index,再次进入检验index
var lawList = parent_job.getVariable("lawList").replace("[","").replace("]","").split(","); var lawSize = new Number(parent_job.getVariable("lawSize")); var index = new Number(parent_job.getVariable("index"))+1; if(index<lawSize){ parent_job.setVariable("lawID",lawList[index]); } parent_job.setVariable("index",index); true;
- 递增lawID范围,一次小循环后,重置startIndex,endIndex的值
var lawCount = new Number(parent_job.getVariable("lawCount")); var startIndex = new Number(parent_job.getVariable("startIndex")); var endIndex = new Number(parent_job.getVariable("endIndex")); if(endIndex<lawCount){ parent_job.setVariable("startIndex",endIndex); parent_job.setVariable("endIndex",endIndex+100); } true;
- 重新检验startIndex的值,直到不通过,跳出循环,完成抽取
总结:
- 提供方改不动,没办法只能循环调用
- 只是自己琢磨的kettle处理方式,我相信一定有更好的处理方式
- job应该是相对独立的模块,结束后就会释放内存??所以不会出现溢出??希望大神解答