是否有一种普遍接受的方法来使用Java EE返回大量对象?
例如,如果您有一个拥有数百万个对象的数据库ResultSet,您将如何将这些对象返回给(远程)客户端应用程序?
另一个例子 - 更接近我实际做的 - 将聚合来自数百个来源的数据,将其标准化,并将其作为单个“列表”逐步传输到客户端系统。
由于所有数据都无法容纳在内存中,我认为有状态的SessionBean和某种回调到服务器的自定义Iterator的组合可以解决问题。
所以,换句话说,如果我有像Iterator<Data> getData()
这样的API,那么实施getData()
和Iterator<Data>
的好方法是什么?
过去你是如何成功解决这个问题的?
答案 0 :(得分:2)
绝对不要将整个数据库复制到Java的内存中。这没有任何意义,只会使事情变得不必要地缓慢和占用内存。而是在数据库级别引入分页。您应该只查询实际需要在当前页面上显示的数据,就像Google一样。
如果您实际上很难正确地实现这一点和/或为特定数据库确定SQL查询,那么请查看this answer。对于JPA / Hibernate等效项,请查看this answer。
更新(这实际上会改变整个问题主题......),这是一个基本的(伪)启动示例:
List<Source> inputSources = createItSomehow();
Source outputSource = createItSomehow();
for (Source inputSource : inputSources) {
while (inputSource.next()) {
outputSource.write(inputSource.read());
}
}
通过这种方式,您可以有效地在Java内存中使用单个条目而不是整个集合,如下面的(低效)示例所示:
List<Source> inputSources = createItSomehow();
List<Entry> entries = new ArrayList<Entry>();
for (Source inputSource : inputSources) {
while (inputSource.next()) {
entries.add(inputSource.read());
}
}
Source outputSource = createItSomehow();
for (Entry entry : entries) {
outputSource.write(entry);
}
答案 1 :(得分:1)
使用基于Web的UI时,分页是一个很好的解决方案。但有时候,在一次调用中流式传输所有内容会更有效率。 rmiio库是为此专门编写的,并且已知可以在各种应用服务器中使用。
答案 2 :(得分:0)
如果您的列表很大,则必须假设它不适合内存。或者至少如果你的服务器需要在许多并发访问上处理它,那么你就有很高的OutOfMemoryException风险。
基本上,你所做的就是分页和使用批量阅读。假设您从数据库加载了1千个对象,您将它们发送到客户端请求响应。然后循环直到处理完所有对象。 (参见BalusC的回复)
客户端问题相同,您可能需要将数据流式传输到文件系统以防止出现OutOfMemory错误。
请注意:可以从数据库中加载数百万个对象作为管理任务:例如执行备份和导出某些“例外”案例。但是你不应该将它用作任何用户可以做的请求。它会很慢并耗尽服务器资源。