多线程环境中的 JDBC 事务
Posted
技术标签:
【中文标题】多线程环境中的 JDBC 事务【英文标题】:JDBC transactions in multi-threaded environment 【发布时间】:2018-02-23 08:51:47 【问题描述】:开发一个Java应用程序在多个线程之间共享一个Connection,就会出现并发问题。
如果线程 A 更新表 T 中的记录 1,同时线程 B 对表 T 中的记录 1 发出 SELECT,我如何确保线程 B 读取线程 A 的更新值?
java.sql.Connection 提供了带有 begin()、commit() 和 rollback() 的事务,但是这个过程是否也包括数据正确性?
我想我错过了什么。
【问题讨论】:
使用知名的连接池 不要分享Connection
。它不是用来分享的。
【参考方案1】:
两点:
-
您不应该在线程之间共享
jdbc.Connection
,至少对于任何“认真生产”的代码,请参阅here。出于演示目的,我认为共享连接是可以的;
如果一个线程在相关 DB 事务提交后从 DB 中读取数据,它将看到另一个线程写入的数据。
关于你的第二个问题
线程 B 会超时,直到第一个事务有 commit() 或 rollback()
-- B
将阻塞直到A
tx 完成(通过提交或回滚)如果:
B
尝试更新/删除由A
更新的同一表行,并且...
A
使用 SELECT ... FOR UPDATE
在 DB 级锁定下更新该行。
您可以使用两个控制台(例如,使用 PostgreSQL psql
)获得此行为,每个控制台代表一个线程:
在A
控制台输入以下:
BEGIN;
SELECT some_col FROM some_tbl WHERE some_col = some_val FOR UPDATE;
现在在B
控制台输入:
BEGIN;
UPDATE some_tbl SET some_col = new_val WHERE some_col = some_val;
您应该看到UPDATE
阻塞,直到在A
您执行COMMIT
或ROLLBACK
。
上面的解释使用了单独的 DB 连接,就像 Java JDBC 连接池一样。我认为,当您在 Java 线程之间共享单个连接时,如果连接被其他线程使用,与 DB 的任何交互都会阻塞。
【讨论】:
它实际上是一个小的演示应用程序。我缺少的是:如果我在线程 A 中开始()一个事务,并且在我开始()来自线程 B 的另一个事务之后,线程 B 是否会超时,直到第一个事务具有 commit() 或 rollback() ?还是线程 B 会抛出 SQLException? 3. Java 中的事务是用一个线程使用连接的想法来实现的。当事务打开时,底层实现调用在连接上开始。成功返回时调用commit,如果有运行时异常调用rollback。 @BorisPavlović 理解这个概念。现在又出现了一个问题。从线程 A(使用连接 A)开始事务(调用 begin())是否会锁定相关记录,直到提交或回滚更改?或者线程 B(带有连接 B)是否仍然能够在不等待线程 A 提交/回滚的情况下选择这些记录? 我会说后者,但是,当有一个简单的解决方案来避免风险时,它是无关紧要的。 @BorisPavlović 可能我把事情复杂化了。这个简单的解决方案是什么?每个线程一个连接?【参考方案2】:Jdbc 是一种被广泛采用的标准,但遵守程度参差不齐,因此对什么是安全的进行笼统的陈述可能并不好。
我不希望有任何东西可以防止由多个线程进行的语句执行、提交和回滚被交错。最好的情况是,一次只有一个线程可以使用连接,其他线程阻塞,使多线程无用。
如果您不想为每个线程提供连接,您可以让线程将工作项提交到一个队列,该队列由处理所有 jdbc 工作的单个工作线程使用。但是引入连接池对现有代码的影响可能较小。
一般来说,如果您有并发更新和读取,那么它们会按照它们发生的顺序发生。锁定和隔离级别为并发事务提供一致性保证,但如果尚未开始其事务,则这些不适用。您可以在每一行上使用状态标志、版本号或时间戳来指示更新发生的时间。
如果您有很多更新,最好将它们收集到一个平面文件中并执行批量复制。它可以比使用 jdbc 快得多。然后在 jdbc 中执行选择更新。
【讨论】:
从技术上讲,JDBC 要求连接是线程安全的,但这并不意味着这些线程是相互隔离的。这仍然意味着所有这些线程应该在同一个事务中合作,并协调它们的动作,这样它们就不会做干扰的工作(例如,一个线程提交事务,而另一个线程仍在工作,等等)。这使得从多个线程访问单个连接充其量不是很有用,最坏的情况是成为竞争条件出没的错误的避风港。以上是关于多线程环境中的 JDBC 事务的主要内容,如果未能解决你的问题,请参考以下文章