非常开放的问题, 我需要编写一个java客户端,它从Oracle数据库中读取数百万条记录(比如说帐户信息)。将其转储为XML并通过webservices将其发送给供应商。
最优化的方法是什么?从获取数百万条记录开始。我走了JPA / hibernate路线,我从记忆错误中获取了200万条记录。
JDBC是更好的方法吗?在我去的时候获取每一行并构建XML?还有其他选择吗?
我不是Java方面的专家,所以我们非常感谢任何指导。
答案 0 :(得分:2)
我们在某个时候遇到了类似的问题,我们的记录大小超过了2M。这就是我们接近的方式。
由于大量开销(如创建大型POJO),如果要将数据转储到XML,基本上不需要使用任何OR映射工具。
简单的JDBC是要走的路。这样做的主要优点是它返回一个ResultSet
对象,实际上并不包含所有结果。因此解决了在内存中加载整个数据的问题。在我们遍历ResultSet
接下来是XML文件的创建。我们创建一个XML文件并打开,而不是Append mode。
现在循环遍历Resultset
对象,我们创建XML片段,然后将其附加到XML文件。这一直持续到整个Resultset
被迭代。
最后我们所拥有的是XML文件将所有记录。
现在,为了共享此文件,我们创建了一个Web服务,如果文件可用,它将返回此XML文件的URL(存档/压缩)。
客户端可以在此后的任何时间下载此文件。
请注意,这不是同步系统,这意味着客户端进行呼叫后该文件不可用。由于创建XML调用需要花费大量时间,因此HTTP wold通常会超时,因此这种方法。
您可以从中获取线索。希望这会有所帮助。
答案 1 :(得分:1)
对于这个大小的数据,你可能可以通过启动更多内存的java来逃脱。启动Java时,请使用-Xmx
和-Xms
签出。
如果您的数据真的太大而无法存储在内存中,但又不足以保证对不同技术的投资,请考虑以块的形式运行。这是否必须立即完成?你可以将数据分成10个块并独立完成每个块吗?如果必须一次完成,你可以从数据库中流式传输数据,然后将其流式传输到文件中,忘记你所做的事情(保持JVM中的内存使用率低)?
答案 2 :(得分:1)
使用ResultSet#setFetchSize()
优化从数据库中获取的记录。
请参阅What does Statement.setFetchSize(nSize) method really do in SQL Server JDBC driver?
在JDBC中,
ResultSet#setFetchSize(int)
方法非常重要 JVM控制时的性能和内存管理 从JVM到数据库的网络调用次数 相应地用于ResultSet
处理的RAM量。
答案 3 :(得分:1)
按照之前的答案解释,以块的形式阅读记录。
使用StAX http://stax.codehaus.org/将记录块流式传输到XML文件,而不是将所有记录流式传输到一个大型文档中
保持冷淡
答案 4 :(得分:0)
就Hibernate方面而言,使用SELECT
查询(而不是FROM
查询)来获取以防止填充缓存;或者使用statelessSession
。另外,请务必使用scroll()
代替list()
。建议将hibernate.jdbc.fetch_size
配置为类似200的内容。
在响应方面,XML是一个非常糟糕的选择,因为解析很困难。如果已设置,请确保使用流式XML序列化程序。例如,XPP3库包含一个。
答案 5 :(得分:0)
虽然合理的Java方法可能涉及将XML的StAX构造与分页结果集(简单的JDBC或JPA)结合使用,但请记住,您可能需要一直锁定数据库以进行更新,这可能会或可能会在你的情况下是不可接受的。
我们采用了一种不同的,以数据库为中心的方法,使用INSERT
和UPDATE
上的存储过程和触发器来生成对应的XML节点每行/ [块]数据。这样可以不断确保250GB +的原始数据及其XML表示(~10 GB)是最新的,并且可以减少(没有双关语)导出到单纯的连接问题。
答案 6 :(得分:0)
你仍然可以使用Hibernate来获取数百万的数据,只是你不能在一轮中完成它,因为数百万是一个很大的数字,当然你会有内存不足的例外。您可以将其划分为页面,然后每次都转储到XML,这样记录就不会保存在RAM中,您的程序也不需要如此大的内存。
我之前的项目中有两种常用的方法。不幸的是我不喜欢使用HQL,所以我没有代码。
所以这里INT_PAGE_SIZE
是你想要每轮获取的行数,而getPageCount
是获取要获取所有记录的总轮数。
然后paging
将逐页获取记录,从1到getPageCount
。
public int getPageCount(Criteria criteria) {
ProjectionList pl = Projections.projectionList();
pl.add(Projections.rowCount());
criteria.setProjection(pl);
int rowCount = (Integer) criteria.list().get(0);
criteria.setProjection(null);
if (rowCount % INT_PAGE_SIZE == 0) {
return rowCount / INT_PAGE_SIZE;
}
return rowCount / INT_PAGE_SIZE + 1;
}
public Criteria paging(Criteria criteria, int page) {
if (page != -1) {
criteria.setFirstResult((page - 1) * INT_PAGE_SIZE);
criteria.setMaxResults(INT_PAGE_SIZE);
}
return criteria;
}