2

我有一种从数据库中获取对象负载的方法,该方法返回一个Iterable.

现在,我正在从数据库加载结果集,从中构建对象并使用这些对象填充集合。

显然,我的内存受限于使用这种方法可以加载多少数据以及如果我用完了坏事发生。

我想将实现修改为从数据库中分块数据,而不是一次获取所有数据,然后通过Iterable接口将结果对象公开给客户端。我的数据库驱动程序可以尽其所能,所以我的第一个想法是这样做的自定义实现Iterable

这是一个好方法吗?它让我觉得运行时或库中可能已经支持的东西 - 请不涉及 ORM 解决方案。

4

2 回答 2

3

就个人而言,我能想到的最简单的解决方案是将 a 实现Iterator为围绕 a 的薄包装器ResultSet。这有几个优点:

  • 您不需要提供可重现的 SQL 语句(例如,您可以流式传输未排序的结果)
  • 您不需要依赖可重复读取,这可能会很昂贵
  • 如果您的 JDBC 驱动程序很好,那么您可以使用它的流式结果功能(警告:一些 JDBC 驱动程序总是在您开始迭代它时立即获取完整结果!)
  • 您不需要重新启动Iterator(Iterable.iterator()可以调用两次,这使得这很复杂)。
  • 不“记住”以前返回的数据意味着内存需求可以保持很低

它也有一些缺点:

  • 您的Iterator实现实际上成为了外部资源,因为它绑定了 JDBC 资源:它必须以某种方式“关闭”,使其更难使用
  • 如果Iterator挂起更长的时间,那么这会让 JDBCConnection挂起,这可能在其他地方需要(在完成之前你不能将它返回到池中Iterator)。

另一种方法是实现一个List(或Collection),根据需要延迟恢复其数据的一部分。这可以更好地使用,但构建起来要复杂得多(正确!)。此外,如果内存限制很重要,那么您需要添加一种机制来丢弃以前恢复的对象。

于 2011-10-28T08:45:19.647 回答
1

我已经在我的一个应用程序中实施了 Joachim 建议的方法。我实现了一个DestroyableIterator包含destroy()方法的接口,在ResultSet包装器实现的情况下,该方法关闭了ResultSet. (一些库提供了这个接口,但我没有看到为了 3 行接口定义而引入库依赖项的意义。)

我还捕获了SQLExceptions 并将它们翻译成(未经检查的) Spring DataAccessExceptions,以便通过迭代器next()hasNext()方法传播它们。

关于持有资源的观点是有效的;我使用 the 来控制应用程序代码DestroyableIterator,因此有各种超时机制来避免ResultSet长时间保持实时状态。

于 2011-10-28T08:53:54.543 回答