如何在多线程环境中生成 PreparedStatements?

Posted

技术标签:

【中文标题】如何在多线程环境中生成 PreparedStatements?【英文标题】:How to generate PreparedStatements in a multi-thread-environment? 【发布时间】:2011-10-21 13:11:35 【问题描述】:

我有一个多线程代码的工作版本,但是我对我的 PreparedStatement-wrapper 类是非线程安全的感到不满意。所以我决定在ThreadLocal 中生成 PreparedStatements,以使包装器线程安全。

SQLExceptions 立即开始向我招手。潜在的 Oracle 错误是 ORA-00060 deadlock detected,根据互联网,它应该只发生在写入场景中。我的陈述都是只读的。它出现在一些我既没有听说过也没有有意识地访问过的晦涩的 ACL 包中。

我花了一些时间和精力准备并测试了一个假设,即生成 Connection 对象并从 DataSource 对象中准备来自该对象的语句不应同时发生,因为访问控制数据库可能不是“线程安全的”(尽管 DataSource 肯定是)。有人可以确认或否认这一发现吗?

如果确实如此,是否有最佳实践来避免在多线程应用程序中同时生成 PreparedStatements?

编辑:如询问异常的文本:

Caused by: java.sql.SQLException: ORA-00604: error occurred at recursive SQL level 1
ORA-00060: deadlock detected while waiting for resource
ORA-06512: at "XXX.PKG_ACL", line 129
ORA-06512: at "XXX.PKG_ACL", line 459
ORA-06512: at "XXX.PKG_UTILS", line 1933
ORA-06512: at line 6

【问题讨论】:

【参考方案1】:

有人可以确认或否认这一发现吗?

我没有听说过类似的东西,如果它确实存在,它可能纯粹是一个实现细节。您可以发布您的堆栈跟踪(当然是通过剥离个人信息)吗?

另外,您为什么要尝试使PreparedStatement 线程安全而不是依赖于准备好的语句池/缓存?或者更具体地说,什么样的分析促使你实现ThreadLocalPreparedStatement

【讨论】:

我有一个场景,其中包含一组固定的 n 个数据库访问器,所有这些访问器都有非常个人的 PreparedStatement 来访问数据库。我理解,理论上数据源应该负责池化。问题似乎是,同时生成 n 个 PreparedStatements 会导致数据库死锁。我不想让语句线程安全。【参考方案2】:

一个语句属于一个连接,一个连接不能真正并发使用。一个线程通常应该首先“拥有”一个连接,然后再对其执行语句。所以就按照成语来吧

1 check out connection
2 prepare statement
3 execute query
4 return connection

你不能避免[1]和[4],它们是必要的;如果合并的话,反正也不会太贵。

你想要缓存 [2],这也不是必须的,驱动程序可能已经做了缓存。

【讨论】:

我不以多线程方式访问连接。代码是(或多或少)run() datasource.getConnection().prepareStatement(sql); do_some_stuff()。数据源是线程安全的,但我相信数据库可能不是“线程安全的”,尽管 jdbc 在其之上做了任何事情。

以上是关于如何在多线程环境中生成 PreparedStatements?的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 Mac OSX 在 Python 中生成线程和初始化 Qt 应用程序

我如何使用在 Jmeter 的下一个线程中生成的令牌

如何在多线程环境中捕获 SIGABRT?

如何保护可能在多线程或异步环境中使用的资源?

如何在多线程环境下实现FIFO队列?

Spring在多线程环境下如何确保事务一致性