1

我在 Spring JDBC DAO 中处理大量数据。DAO 直接在对象上返回一个迭代器,该对象使用take()对有界BlockingQueue进行操作,而检索操作发生在单独的线程中(使用ExecutorService)。

在此线程中,我看到以下行为:检索有效,但对ResultSet的某些调用导致调用挂起。这些电话是

  • isClosed()
  • isLast()

但不是

  • isAfterLast()
  • isBeforeFirst()
  • 是第一()

显然我需要知道最后一个元素是什么(为了将一个特殊元素插入到阻塞队列中,在迭代器 hasNext() 方法中产生 false )。我可以通过在将对象放入BlockingQueue之前找出ResultSet中的行数来解决它,但这感觉有点笨拙。是否有使用 ResultSet 的线程安全方式?

切换到多线程数据源(我测试了 C3POs ComboPooledDataSource)似乎没有帮助。

注意:这个问题是我首先(错误地)在这里发现的

4

2 回答 2

1

我不认为这java.sql.ResultSet是线程安全的,尽管在 javadoc 中确实没有提到这一点。ResultSet如果从不同线程调用方法导致这些方法调用挂起,我一点也不感到惊讶。

作为替代方案,我建议让您的检索线程ResultSet作为BlockingQueue. 然后检测结果集的结尾并将 EOF 标记放在队列中变得微不足道。

JDBC 中用于迭代非常大的结果集的一般首选机制是使用 的fetchSize属性java.sql.Statement,尽管这高度依赖于数据库和 JDBC 驱动程序。我知道 Oracle 驱动程序支持此设置,但不确定其他设置。如果驱动程序决定在给您第一行之前需要将整个结果集提取到内存中,那么无论您做什么,您都无法在获取下一行时处理第一行。

于 2009-09-09T12:55:31.293 回答
1

正确的解决方案是设置适当的ResultSet类型。isLast()支持默认的“ TYPE_FORWARD_ONLY”ResultSet的类型可以通过使用PreparedStatementCreator而不是 SQL 字符串来设置,例如对JdbcTemplate的query()调用。此类实例是通过PreparedStatementCreatorFactory获取的。在这样的工厂中,可以设置ResultSet的类型(例如"TYPE_SCROLL_INSENSITIVE" )。

于 2009-10-01T11:41:45.243 回答