在Spring中同时访问JDBC ResultSet

时间:2009-09-09 09:26:49

标签: spring jdbc concurrency thread-safety dao

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

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

  • isClosed()
  • isLast会()

但不是

  • isAfterLast()
  • isBeforeFirst()
  • isFirst()

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

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

注意:此问题首先(错误地)由我here

标识

2 个答案:

答案 0 :(得分:1)

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

作为替代方案,我建议将检索线程作为ResultSet的唯一用户,将行拉出,然后将数据本身转储到BlockingQueue。然后检测结果集的结尾并将您的EOF标记放在队列上变得微不足道。

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

答案 1 :(得分:1)

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