JDBC事务与连接澄清

时间:2013-03-26 16:22:42

标签: java sql multithreading postgresql transactions

我正在使用JDBC与我的Postgres数据库交谈。如果我的整个应用程序都运行一个连接,即只有一次调用;

DriverManager.getConnection("jdbc:postgresql://host:5432/database", user, pass);

但是这个Connection对象是在Java中的多个线程之间共享的,我是否正确地假设任何使用SQL事务(BEGINCOMMIT样式)的尝试都只是考虑到Java线程交错的可能性,会非常混乱和破碎吗? Connection对象是否知道'哪个Java线程正在使用它来进行查询?

每个Java线程是否应该有一个Connection对象并以这种方式使用SQL事务?或者我应该使用synchronized

在Java中执行所有事务隔离

3 个答案:

答案 0 :(得分:14)

只是详细说明现有答案:

PgJDBC's Connection object is thread-safe,但仅限于声明级别。在自动提交模式下由多个线程使用时,它不会崩溃或产生错误的结果,但它不会为您隔离不同的线程事务。根据文档,您需要使用连接池。

实际上有很多方法可以在多个线程之间使用连接:

  • 使用内部连接池从中获取连接,执行工作并将其返回到池中。对于大多数应用程序来说,这是一个非常可取Java存在许多JDBC连接池实现,因此不要自己滚动。 dbcpc3p0是两种流行的实现,但如果您使用的是servlet环境或应用服务器,则通常应该使用服务器的连接池,而不是自带。

  • 使用pgbouncer或pgpool-II等外部连接池,并自由打开/关闭它。这稍微慢一点,并且主要是在应用程序无法或由于各种原因不应在内部池连接时使用的选项。您可能不需要这样做,除非您需要将总连接数限制到数据库并在多个应用程序或应用程序实例之间共享它们。

  • 不使用游泳池并自由打开/关闭连接。这非常低效。不要这样做。

  • 使用线程本地存储为每个线程保持连接。这样做可行,但效率极低,因为每个开放连接在空闲时占用数据库服务器资源。除非您在事务池模式下使用像PgBouncer这样的外部连接池,否则不要这样做,在这种情况下没关系。

  • 仅使用单个连接并在synchronized块中包装事务,在Connection实例上进行同步。这将有效并将有效地使用数据库连接,但会限制线程的性能。除了玩具/便利应用之外,它通常不是一个好的设计。

  • 仅使用具有自己专用线程的单个连接。是否有其他连接通过FIFO队列,生产者/消费者样式传递描述要对该线程完成的工作的数据结构。如果线程花费大部分时间来处理CPU繁重或其他非数据库工作并且仅需要有限的数据库访问,则此方法可行。使用它而不是使用连接池的唯一原因是,如果出于某些外部原因限制使用单个连接,但如果你是这样,那么它可能是一个不错的选择。

但是,一般情况下,您应该只使用连接池并完成它。

答案 1 :(得分:5)

  

我是否正确地假设任何使用SQL事务(BEGINCOMMIT样式)的尝试只会非常混乱和破坏,因为Java线程可能会交错?< / p>

这是绝对正确的。

  

Connection对象是否“知道”哪个Java线程正在使用它来进行查询?

不,它没有。

  

每个Java线程是否应该有一个Connection对象并以这种方式使用SQL事务?

是的,这是一种做法。 “每线程连接”分配的缺点是可能会打开比您需要的更多连接,从而导致资源的次优使用。您也可以仅在线程需要时打开连接,并在线程完成RDBMS访问后关闭它。如果您使用此路由,请确保使用连接池以减少多次重新打开连接的开销。

答案 2 :(得分:2)

Does the Connection object 'know' which Java thread is using it to make queries?

不,连接对象不知道哪个java线程正在使用它。

每个Java线程是否应该有一个Connection对象并以这种方式使用SQL事务? 或者我应该使用synchronized?

在Java中执行所有事务隔离

我们应该使用特定于数据库的jdbc连接池数据源来执行事务,这样当连接对象没有用时,连接将返回池而不进行垃圾回收。这样,应用服务器就可以优化它的连接初始化性能。

此外,您应该在Update Operation期间使用synchronized方法调用,因为这样可以在生产中实现更安全的操作。

相关问题