多线程环境中的JDBC事务

时间:2017-09-14 11:30:27

标签: java multithreading jdbc transactions

开发在多个线程之间共享单个连接的Java应用程序,会出现并发问题。

如果线程A更新表T中的记录1,同时线程B在表T中的记录1上发出SELECT,我如何确保线程B读取线程A的更新值?

java.sql.Connection提供了带有begin(),commit()和rollback()的事务,但是这个过程是否也涵盖了数据的正确性?

我想我错过了一些东西。

2 个答案:

答案 0 :(得分:3)

Jdbc是一个被广泛采用但标准不均衡的标准,对于什么是安全的做出彻底的陈述可能并不好。

我不希望有任何东西可以保持语句执行以及多个线程的提交和回滚不会交错。最好的情况是,一次只有一个线程可以使用连接而其他线程阻塞,使多线程无用。

如果您不想为每个线程提供连接,则可以让线程将工作项提交到由处理所有jdbc工作的单个工作线程使用的队列。但是,引入连接池对现有代码的影响可能较小。

一般情况下,如果您有并发更新和读取,则它们按照它们发生的顺序发生。锁定和隔离级别为并发事务提供了一致性保证,但如果尚未启动其事务,那么这些事务并不适用。您可以在每行上具有状态标志,版本号或时间戳,以指示何时发生更新。

如果您有大量更新,最好在平面文件中收集它们并执行批量复制。它可以比使用jdbc快得多。然后在jdbc中执行选择的更新。

答案 1 :(得分:2)

两点:

  1. 您不应在线程之间共享jdbc.Connection,至少对于任何“认真生产”代码,请参阅here。出于演示目的,我认为,共享连接是可以的;
  2. 如果线程在提交相关数据库事务后从DB读取,则会看到另一个线程写入的数据。
  3. 关于你的第二个问题

      

    将线程B超时,直到第一个事务具有commit()或rollback()

    - B将阻止A tx完成(通过提交或回滚),如果:

    1. B尝试更新/删除A正在更新的同一表格行,并且......
    2. A使用SELECT ... FOR UPDATE更新数据库级锁定下的该行。
    3. 您可以使用两个控制台(例如,使用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#import <UIKit/UIKit.h> @interface UIViewController (AlertExtension) - (void) showNoHandlerAlertWithTitle:(NSString *)title andMessage: (NSString*)message; - (void) showAlertWithTitle:(NSString *)title andMessage:(NSString*)message buttonTitles:(NSArray<NSString *>*)titles andHandler:(void (^)(UIAlertAction * action))handler; @end

      以上说明使用单独的数据库连接,就像Java JDBC连接池一样。当你在Java线程之间共享单个连接时,我认为,如果某个其他线程使用了连接,那么与DB的任何交互都将阻塞。