`
dyllove98
  • 浏览: 1409203 次
  • 性别: Icon_minigender_1
  • 来自: 济南
博客专栏
73a48ce3-d397-3b94-9f5d-49eb2ab017ab
Eclipse Rcp/R...
浏览量:39180
4322ac12-0ba9-3ac3-a3cf-b2f587fdfd3f
项目管理checkList...
浏览量:80257
4fb6ad91-52a6-307a-9e4f-816b4a7ce416
哲理故事与管理之道
浏览量:133372
社区版块
存档分类
最新评论

java千万级别数据生成文件思路和优化

阅读更多

 

欢迎大家访问我的个人网站 萌萌的IT人,后续所有的文章都会在此发布

--------------------------------------------------------------------------------------------

              一年前写过一个百万级别数据库数据生成配置xml文件的程序,程序目的是用来把数据库里面的数据生成xml文件.程序可以配置多少文件生成到一个文件中去.

 

              程序刚开始设计的时候说的是最多百万级别数据,最多50W数据生成到一个xml文件里面去,所以在做测试的时候自己也只是造了100W的数据并没有做过多数据量的测试,然后问题就来了....由于程序使用的局点数据量巨大,需要生成xml文件的客户资料接近千万级别的程度,而现场对程序的配置大约是100W条数据生成一个xml文件里面去,程序在这样的大数据量下面偶尔会有崩溃.

 

              最近几天现场催的比较紧,最近抽空把这个问题处理了一下,在解决问题的过程中我把解决的步骤和方法记录了下来,正好和大家共享一下

 

现场提的问题概况:

    数据量:生成xml,每个文件100W+ 条的数据

    内存控制:最好不要超过512M

    问题详情:在处理70W左右的时候内存溢出

 

一、先来看一下程序要生成的xml文件的结构

 

<File>
  <FileType>1</FileType>
  <RType>12</RType>
  <Version>03</Version>
  <BNo>004</BNo>
  <FileQ>5</FileQ>
  <FNo>0006</FNo>
  <RecordNum>1000000</RecordNum>
  <!-- 上面是文件头  下面是百万个<RecordList>  -->
  <RecordList>
    <Msisdn>10350719507</Msisdn>
    <State>1</State>
    <StartDate>20110303</StartDate>
    <Date>20110419</Date>
    <Balance>45000</Balance>
  </RecordList>
   ...  <!-- 可能百万个  <RecordList> 块-->
 </File>

 

 

二、给大家说一下如何把大数据生成xml文件

 

          1、小数据量的情况下    <  1W条数据

 

               比较好用的方法是使用开源框架,比如XStream 直接把javabean 生成 xml

               优点:api操作简单,方便维护

               缺点:数据量大的情况下太消耗内存

 

          2、大数据量生成一个xml文件(本程序采用的方法)

 

               自己做的一个可以使用极少的内存生成无限制大的xml文件框架由3部分生成xml文件

               第一部分:生成文件头  

                            例如: xxx.toXML(Object obj, String fileName)

               第二部分:通过每次向文件里面追加3000(可配置)条数据的形式生成文件块  

                            例如:xxx.appendXML(Object object);  //object 可以是ArrayList 或者一个单独的javaBean

               第三部分:生成xml文件尾巴   

                           例如:xxx.finishXML();

      

               程序中的调用:调用xxx.toXML(Object obj, String fileName) 生成文件头之后,可以循环从数据库中读取数据生成ArrayList,通过xxx.appendXML(Object object) 方法追加到xml文件里面,xxx.finishXML() 对文件进行收尾

 

               对框架说明:我上面提供的例子有文件头 + 文件块 + 文件尾巴. 如果和你们的实际使用文件不太一致的话,可以参考上面提供的思路修改一下即可,主要的方法是把相同的文件块部分分离出来通过追加的形式写入xml文件.

 

                      有了思路之后,大家可以尝试着自己写一个类似的大数据处理框架(千万级别以上),如何有什么需要帮助的可以直接联系我,因为是公司的程序,不太敢放出来,怕......

     

三、我是如何测试性能和优化的

 

               1、手动排除

 

                    根据文件崩溃时候的日志发现是在生成xml的框架里面报的错误,第一想到的是框架有些资源没有释放.于是把自己做的文件生成框架整体的排查了一遍,并且自己写个简单程序生成200万条数据,使用xml框架生成一个xml文件,整个生成过程中任务管理器(xp)查看程序对应的java进程使用的内存基本在20M左右,因此排除框架的问题.怀疑是数据库查询和调用框架的部门出现问题.

                    检测了一遍主程序的关键部分代码,优化了一下字符串处理.手动的释放一些对象的内存(例如:调用ArrayList.clear(),或者把对象置空等),分配512内存后运行程序,60万数据的时候内存溢出,因为能主动释放的对象都已经释放掉了,还是没有解决,果断放弃看代码,准备使用JProfile进行内存检测.

 

               2、手动排除没有解决,借助内存分析工具JProfile进行排除

 

                    通过在数据库中生成300W条数据,在JProfile上面多跑程序,一边运行,一边调用JProfile 提供的执行GC按钮主动运行垃圾回收,运行50W数据后,通过检测中发现 java.long.String[] 和 oracle.jdbc.driver.Binder[] 两个对象的数目一直保持在自增状态,而且数目基本上差不多,对象数目 都在200W以上,由于java.long.String[]对象是需要依赖对象而存在的,因此断定问题就出在oracle.jdbc.driver.Binder[]上面,由于改对象存在引用导致String[]不能正常回收.

 

               3、通过在JProfile对象查看对象的管理

 

                   检测到oracle.jdbc.driver.Binder 被 oracle.jdbc.driver.T4CPreparedStatement 引起,而T4CPreparedStatement正好是Oracle对jdbc OraclePreparedStatement的具体实现,因此断定是在数据库处理方面出现的问题导致oracle.jdbc.driver.Binder对象不能正常释放,通过再一次有目的的检测代码,排查jdbc数据查询的问题,把问题的矛头直至数据库的批处理和事务处理.因此程序是每生成一个文件成功后,会把已经处理的数据转移到对应的历史表中进行备份,而再个表操作的过程中使用了批处理和事务,使用批处理主要是保证执行速度,使用事务主要是保证同时成功和失败。

               4、又因此程序每次从数据库中查询3000条数据处理,所以准备监控oracle.jdbc.driver.Binder的对象数目是否和查询次数对应.,通过在程序中Sysout输出查询次数 + JProfile运行GC测试 Binder,数据匹配,证实是java在数据库批处理的过程中有些问题.

               5、专门把批处理代码提取出来通过JProfile内存分析.最终问题定位完毕.

 

                    原因如下:100W数据生成一个文件的过程中,等文件生成完毕之后才能把数据库中的数据备份到历史表中,这个时候才能进行事务的提交,也就是执行commit(), 并且删除原表数据,100W数据按照3000一批写入文件,每批次只是通过 PreparedStatement.addBatch();加入到批次里面去,并没有执行PreparedStatement.executeBatch(),而是在commit()之前统一调用的PreparedStatement.executeBatch(),这样的话PreparedStatement就会缓存100W条数据信息,造成了内存溢出.

错误的方法如下:

 

try{
            conn.setAutoCommit(false);
            pst = conn.prepareStatement(insertSql);
            pstDel = conn.prepareStatement(delSql);
            pstUpdate = conn.prepareStatement(sql);
            ... 
            //totalSize = 100W数据 / 3000一批次
            for (int i = 1; i <= totalSize; i++) {
                
                client.appendXML(list);
               
            }
            // 错误的使用方法
            client.finishXML();
            pst.executeBatch();
            pstDel.executeBatch();
        }
         ...
        finally {
            try {
                if (isError) {
                    conn.rollback();
                }
                else
                    conn.commit();
               ...
            }
          ...
        }

 

正确的方法如下

          try{

            conn.setAutoCommit(false);
            pst = conn.prepareStatement(insertSql);
            pstDel = conn.prepareStatement(delSql);
            pstUpdate = conn.prepareStatement(sql);
            ... 
            //totalSize = 100W数据 / 3000一批次
            for (int i = 1; i <= totalSize; i++) {
                list = 从数据库中查询3000条数据
                client.appendXML(list);

               pst.executeBatch();
               pstDel.executeBatch();
            }
            client.finishXML();
            
        }
         ...
        finally {
            try {
                if (isError) {
                    conn.rollback();
                }
                else
                    conn.commit();
               ...
            }
          ...
        }

 

               如果碰到和我一样的需要给大家一个提醒.

               oracle在每次执行executeBatch();进行批处理的时候,当前connection对应的rownum会根据操作的结果发生变化.

 

               在执行pst.executeBatch(); 之后,当前连接的 rownum 数就会发生变化. 因此凡是通过rownum查询数据的程序都要小心这一点

 

 

                下一篇将整理写java大数据(千万级别以上的)处理,包括 ftp大数据处理、文件生成大数据处理、数据库转移大数据处理、文件读取大数据处理等等. 

 

        

                       <千万级别数据生成xml文件> by dyllove98 @ http://jlins.iteye.com

                        转载请表明出处。

 

 

28
8
分享到:
评论
40 楼 静夜独窗 2014-12-04  

               自己做的一个可以使用极少的内存生成无限制大的xml文件框架由3部分生成xml文件
               第一部分:生成文件头 
                            例如: xxx.toXML(Object obj, String fileName)
               第二部分:通过每次向文件里面追加3000(可配置)条数据的形式生成文件块 
                            例如:xxx.appendXML(Object object);  //object 可以是ArrayList 或者一个单独的javaBean
               第三部分:生成xml文件尾巴  
                           例如:xxx.finishXML();

方法使用的类得告诉我们啊,你可以把代码放出来,把方法名啊,涉及你公司的东西改动应该就可以了吧,还是放代码吧,这样没人能懂啊,你说呢
     
39 楼 唐风今何在 2013-03-05  
文件生成大数据处理,这个出路了么?
38 楼 WAMING5 2012-04-25  
引用
          2、大数据量生成一个xml文件(本程序采用的方法)

               自己做的一个可以使用极少的内存生成无限制大的xml文件框架由3部分生成xml文件
               第一部分:生成文件头 
                            例如: xxx.toXML(Object obj, String fileName)
               第二部分:通过每次向文件里面追加3000(可配置)条数据的形式生成文件块 
                            例如:xxx.appendXML(Object object);  //object 可以是ArrayList 或者一个单独的javaBean
               第三部分:生成xml文件尾巴  
                           例如:xxx.finishXML();
     
               程序中的调用:调用xxx.toXML(Object obj, String fileName) 生成文件头之后,可以循环从数据库中读取数据生成ArrayList,通过xxx.appendXML(Object object) 方法追加到xml文件里面,xxx.finishXML() 对文件进行收尾

这部分文件操作楼主能否给点儿思路,文件操作的文盲呀。先谢楼主了
37 楼 guowei821120 2012-04-20  
rensanning 写道
dyllove98 写道
guowei821120 写道
想知道楼主假如读取2G多xml文件并有运算逻辑的话,有什么好的解决办法

不要使用那些直接生成树的框架就行,可以使用Java Sax解析xml
按照xml文件的顺序一步一步的来解析,在解析xml文件之前,我们要先了解xml文件的节点的种类,一种是ElementNode,一种是TextNode。


推荐看看这篇文章:http://java.dzone.com/articles/xml-unmarshalling-benchmark

多谢,欣赏中
36 楼 mixer_a 2012-04-20  
千万级别的ftp操作有什么技巧吗?
35 楼 mixer_a 2012-04-20  
simhashing 写道
性能是最重要的

34 楼 simhashing 2012-04-19  
性能是最重要的
33 楼 rensanning 2012-04-19  
dyllove98 写道
guowei821120 写道
想知道楼主假如读取2G多xml文件并有运算逻辑的话,有什么好的解决办法

不要使用那些直接生成树的框架就行,可以使用Java Sax解析xml
按照xml文件的顺序一步一步的来解析,在解析xml文件之前,我们要先了解xml文件的节点的种类,一种是ElementNode,一种是TextNode。


推荐看看这篇文章:http://java.dzone.com/articles/xml-unmarshalling-benchmark
32 楼 dyllove98 2012-04-19  
guowei821120 写道
想知道楼主假如读取2G多xml文件并有运算逻辑的话,有什么好的解决办法

不要使用那些直接生成树的框架就行,可以使用Java Sax解析xml
按照xml文件的顺序一步一步的来解析,在解析xml文件之前,我们要先了解xml文件的节点的种类,一种是ElementNode,一种是TextNode。
31 楼 grzrt 2012-04-19  
dyllove98 写道
WAMING5 写道
引用

26 楼 dyllove98 15 分钟前   引用
rensanning 写道
肯定不能这么处理!大致算一下,文中RecordList部分大概145个字符,1000W数据的大小=145*2*10000000/1024/1024/1024=2.7GB 你觉得合适吗


WAMING5 写道
  新手有些个疑惑的地方,在数据从数据查询出来时虽然做了分页处理这样可以使内存保持平稳状态,但是另个一方面,因为XML是不断在追加的,这个过程中XML的大小也是在增加的,既然是追加,那么整个XML是否也是被读到内存中,追加的呢?

1000W数据 的确会生成 2G大的文件,不过不是xml不断追加,是往文件里面追加.

往文件里追加,可以不用把整个文件读到内存里,然后做追加吗。楼主是怎么追加的呢?

标准的io输出流就可以... 看样子你要补充一下io输入输出的知识了,java写文件件的话可不会把文件读取到内存,要是真读取的话也太失败了吧...

adsf
30 楼 guowei821120 2012-04-19  
想知道楼主假如读取2G多xml文件并有运算逻辑的话,有什么好的解决办法
29 楼 WAMING5 2012-04-19  
引用
28 楼 dyllove98 1 分钟前   引用
WAMING5 写道
引用

26 楼 dyllove98 15 分钟前   引用
rensanning 写道
肯定不能这么处理!大致算一下,文中RecordList部分大概145个字符,1000W数据的大小=145*2*10000000/1024/1024/1024=2.7GB 你觉得合适吗


WAMING5 写道
  新手有些个疑惑的地方,在数据从数据查询出来时虽然做了分页处理这样可以使内存保持平稳状态,但是另个一方面,因为XML是不断在追加的,这个过程中XML的大小也是在增加的,既然是追加,那么整个XML是否也是被读到内存中,追加的呢?

1000W数据 的确会生成 2G大的文件,不过不是xml不断追加,是往文件里面追加.


往文件里追加,可以不用把整个文件读到内存里,然后做追加吗。楼主是怎么追加的呢?

标准的io输出流就可以... 看样子你要补充一下io输入输出的知识了,java写文件件的话可不会把文件读取到内存,要是真读取的话也太失败了吧...

呵呵,我文件操作这块儿接触的少,所以XML追加时有疑惑。
28 楼 dyllove98 2012-04-19  
WAMING5 写道
引用

26 楼 dyllove98 15 分钟前   引用
rensanning 写道
肯定不能这么处理!大致算一下,文中RecordList部分大概145个字符,1000W数据的大小=145*2*10000000/1024/1024/1024=2.7GB 你觉得合适吗


WAMING5 写道
  新手有些个疑惑的地方,在数据从数据查询出来时虽然做了分页处理这样可以使内存保持平稳状态,但是另个一方面,因为XML是不断在追加的,这个过程中XML的大小也是在增加的,既然是追加,那么整个XML是否也是被读到内存中,追加的呢?

1000W数据 的确会生成 2G大的文件,不过不是xml不断追加,是往文件里面追加.

往文件里追加,可以不用把整个文件读到内存里,然后做追加吗。楼主是怎么追加的呢?

标准的io输出流就可以... 看样子你要补充一下io输入输出的知识了,java写文件件的话可不会把文件读取到内存,要是真读取的话也太失败了吧...
27 楼 WAMING5 2012-04-19  
引用

26 楼 dyllove98 15 分钟前   引用
rensanning 写道
肯定不能这么处理!大致算一下,文中RecordList部分大概145个字符,1000W数据的大小=145*2*10000000/1024/1024/1024=2.7GB 你觉得合适吗


WAMING5 写道
  新手有些个疑惑的地方,在数据从数据查询出来时虽然做了分页处理这样可以使内存保持平稳状态,但是另个一方面,因为XML是不断在追加的,这个过程中XML的大小也是在增加的,既然是追加,那么整个XML是否也是被读到内存中,追加的呢?

1000W数据 的确会生成 2G大的文件,不过不是xml不断追加,是往文件里面追加.

往文件里追加,可以不用把整个文件读到内存里,然后做追加吗。楼主是怎么追加的呢?
26 楼 dyllove98 2012-04-19  
rensanning 写道
肯定不能这么处理!大致算一下,文中RecordList部分大概145个字符,1000W数据的大小=145*2*10000000/1024/1024/1024=2.7GB 你觉得合适吗

WAMING5 写道
  新手有些个疑惑的地方,在数据从数据查询出来时虽然做了分页处理这样可以使内存保持平稳状态,但是另个一方面,因为XML是不断在追加的,这个过程中XML的大小也是在增加的,既然是追加,那么整个XML是否也是被读到内存中,追加的呢?

1000W数据 的确会生成 2G大的文件,不过不是xml不断追加,是往文件里面追加.
25 楼 dyllove98 2012-04-19  
rensanning 写道
ArrayList初期容量为10,递增算法是乘3除2加1,HashSet(HashMap)初期容量为16,所以如果在知道数据有多少件的前提下最好指定初期容量,避免每次add时容量的调整,从而提高性能。

jiuyuehe 写道
楼主,如果把ArrayList 换成HashSet 更好。java 集合包之各个集合性能分析

对,是这个样子的  
24 楼 dyllove98 2012-04-19  
WAMING5 写道
  新手有些个疑惑的地方,在数据从数据查询出来时虽然做了分页处理这样可以使内存保持平稳状态,但是另个一方面,因为XML是不断在追加的,这个过程中XML的大小也是在增加的,既然是追加,那么整个XML是否也是被读到内存中,追加的呢?

每一个批次都会生成xml串,然后把xml串写入文件之后,清空串。不会增大
23 楼 dyllove98 2012-04-19  
jiuyuehe 写道
楼主,如果把ArrayList 换成HashSet 更好。java 集合包之各个集合性能分析

呵呵,我试试看..
22 楼 rensanning 2012-04-19  
肯定不能这么处理!大致算一下,文中RecordList部分大概145个字符,1000W数据的大小=145*2*10000000/1024/1024/1024=2.7GB 你觉得合适吗

WAMING5 写道
  新手有些个疑惑的地方,在数据从数据查询出来时虽然做了分页处理这样可以使内存保持平稳状态,但是另个一方面,因为XML是不断在追加的,这个过程中XML的大小也是在增加的,既然是追加,那么整个XML是否也是被读到内存中,追加的呢?
21 楼 rensanning 2012-04-19  
ArrayList初期容量为10,递增算法是乘3除2加1,HashSet(HashMap)初期容量为16,所以如果在知道数据有多少件的前提下最好指定初期容量,避免每次add时容量的调整,从而提高性能。

jiuyuehe 写道
楼主,如果把ArrayList 换成HashSet 更好。java 集合包之各个集合性能分析

相关推荐

    Java千万级别数据生成文件思路和优化

    程序刚开始设计的时候说的是最多百万级别数据,最多50W数据生成到一个xml文件里面去,所以在做测试的时候自己也只是造了100W的数据并没有做过多数据量的测试,然后问题就来了....由于程序使用的局点数据量巨大,需要...

    java课程设计(扫雷游戏)(1).doc

    此外,还需利用Java系统提供的类如`File`,`Button`和`JLabel`来实现文件操作、界面元素及交互功能。 **关键技术** - **图形用户界面(GUI)**:使用Java的Swing库构建游戏界面,包括菜单栏、游戏区域和提示信息等。 ...

    java编写的一个小游戏TurnAround

    【标题】"java编写的一个小游戏TurnAround"指出这是一款使用Java编程语言开发的娱乐软件。...总的来说,"TurnAround"是一个展示Java编程技能和游戏设计思路的良好实例,对于学习者和爱好者来说具有很高的参考价值。

    代码生成工具原代码

    它们可以根据预定义的模板或者用户自定义的规则,自动生成如数据访问层、业务逻辑层、控制层等代码,尤其在大型项目或框架应用中十分常见。 描述中提到的“博文链接:https://ruanjiangjx.iteye.com/blog/797013”...

    互联网软件开发&#40;java&#41;大作业题目备选.doc

    【互联网软件开发(Java)大作业题目...以上是各题目涉及到的Java编程知识和设计思路,涵盖了数据结构、算法、文件操作、数据库管理、网络通信、图形界面、游戏开发等多个方面,为互联网软件开发提供了丰富的实践场景。

    对反编译后的smali文件进行分包

    在标题和描述中提到的“根据方法数进而分目录的实现思路”指的是将大量的smali文件按照其包含的方法数量分布到不同的子目录中,以减少单个DEX文件中的方法数量。具体实现步骤如下: 1. **读取smali文件**:首先,...

    JAVA常见的面试题

    以上只是Java面试中可能涉及的部分知识点,实际面试可能会根据应聘者的经验级别和职位要求进行更深入的探讨。在准备面试时,全面掌握这些知识点并能结合实际项目经验进行解答,将大大提高面试成功的几率。同时,思维...

    基于Java的web校园二手平台系统毕业设计(项目报告+答辩PPT+源代码+数据库+截图+部署视频).zip

    数据库设计包括了ER图(实体关系图)、表结构设计、字段类型选择以及索引优化等方面,确保数据的高效存储和检索。 4. **前端技术** 前端界面的开发可能使用了HTML、CSS和JavaScript,配合Bootstrap或Vue.js等前端...

    安卓三级联动省市联动多级联动相关-仿京东城市代码本地json数据可以获取城市代码和城市名字超简单易懂.rar

    2. 解析JSON数据:在Android应用中,使用`org.json`库或者Gson等工具解析JSON文件,将数据转化为Java对象,如`Province`、`City`、`District`类。 3. 创建选择器UI:通常会用到`Spinner`控件或者自定义的`ListView`...

    Android源码

    【Android源码】是开发者深入理解Android系统工作原理和开发应用的重要途径。它包含了操作系统级别的组件,以及应用程序...同时,研究源码也能帮助开发者了解最佳实践,提升编程技巧,并为自定义和优化应用提供思路。

    Kettle 4.4.2源码分析.rar

    通过深入研究Kettle 4.4.2的源码,我们可以更深入地了解其内部运作机制,提升我们的数据处理技能,同时也为定制化开发和性能优化提供了基础。尽管本文只涵盖了部分关键知识点,但实际的源码分析工作远不止于此,需要...

    【spring-boot-seckill分布式秒杀系统 v1.0】从0到1构建的java秒杀系统源码+安装说明

    1、前端优化:活动开始前生成静态商品页面推送缓存和CDN,静态文件(JS/CSS)请求推送至文件服务器和CDN。 2、网络优化:如果是全国用户,最好是BGP多线机房,减少网络延迟。 3、应用服务优化:Nginx最佳配置、Tomcat...

    基于springboot的房屋租赁系统源码数据库.zip

    《基于SpringBoot的房屋租赁系统源码数据库解析》 在当今的互联网时代,房屋租赁系统已经成为日常生活中的一个重要组成部分。...同时,对于有经验的开发者,此系统源码也能提供一些新的设计思路和优化方案。

    基于Java的B2C网上拍卖秒杀与竞价系统设计与实现(项目报告+答辩PPT+源代码+数据库+截图+演示录像).zip

    该压缩包文件包含了一个基于Java实现的B2C网上拍卖秒杀与竞价系统的完整资源,包括项目报告、答辩PPT、源代码、数据库、截图以及演示录像,这是一份全面的毕业设计作品,适合学生参考学习或教师教学使用。...

    QRCode源码包

    通过研究这些源码,开发者不仅可以了解二维码技术的内部工作机制,还可以借鉴其设计思路,自定义二维码生成器或者优化现有解码器。此外,对于学习Java编程和理解软件工程实践,例如面向对象设计、异常处理和模块化...

Global site tag (gtag.js) - Google Analytics