简体   繁体   English

JDBC事务与连接澄清

[英]JDBC Transaction vs Connection Clarification

I am using JDBC to talk to my Postgres database. 我正在使用JDBC与我的Postgres数据库交谈。 If my entire app runs off a single connection, ie there is only ever one call to; 如果我的整个应用程序都运行一个连接,即只有一个呼叫;

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

But this Connection object is shared across multiple threads in the Java, am I right in assuming that any attempt to use SQL transactions ( BEGIN and COMMIT style) is only going to be very confusing and broken, given the potential for the Java threads to interleave? 但是这个Connection对象是在Java中的多个线程之间共享的,我正确地假设任何使用SQL事务( BEGINCOMMIT样式)的尝试只会非常混乱和破坏,因为Java线程可能会交错? Does the Connection object 'know' which Java thread is using it to make queries? Connection对象是否“知道”哪个Java线程正在使用它来进行查询?

Should I have one Connection object per Java thread and use the SQL transactions that way? 我应该为每个Java线程都有一个Connection对象并以这种方式使用SQL事务吗? Or should I perform all my transactional isolation in the Java using synchronized ? 或者我应该使用synchronized在Java中执行所有事务隔离?

Just to elaborate on the existing answers: 只是详细说明现有的答案:

PgJDBC's Connection object is thread-safe , but only on a statement level. PgJDBC的Connection对象是线程安全的 ,但仅限于语句级别。 It won't crash or produce wrong result when used by multiple threads in autocommit mode but it won't isolate different threads' transactions for you. 在自动提交模式下由多个线程使用时,它不会崩溃或产生错误的结果,但它不会为您隔离不同的线程事务。 As per the documentation you need to use a connection pool for that. 根据文档,您需要使用连接池。

There are actually lots of ways to use connections among multiple threads: 实际上有很多方法可以在多个线程之间使用连接:

  • Use an internal connection pool where you fetch connections from, perform work with them, and return them to the pool. 使用内部连接池从中获取连接,使用它们执行工作,并将它们返回到池中。 This is the strongly preferable option for most applications. 对于大多数应用程序来说,这是一个非常可取 Many JDBC connection pool implementations exist for Java, so don't roll your own. Java存在许多JDBC连接池实现,因此不要自己滚动。 dbcp and c3p0 are two popular implementations, but if you're using a servlet environment or app server you should generally use the server's connection pool rather than bringing your own. dbcpc3p0是两种流行的实现,但如果您使用的是servlet环境或应用服务器,则通常应使用服务器的连接池而不是自带连接池。

  • Use an external connection pool like pgbouncer or pgpool-II and open/close connections to it freely. 使用像pgbouncer或pgpool-II这样的外部连接池,并自由打开/关闭它。 This is slightly slower and is mostly an option used where the application cannot or for various reasons should not pool connections internally. 这稍微慢一点,并且主要是在应用程序无法或由于各种原因不应在内部池连接时使用的选项。 You probably don't need to do this unless you need to limit total connection counts to the DB and share them between multiple applications or app instances. 您可能不需要这样做,除非您需要限制数据库的总连接数并在多个应用程序或应用程序实例之间共享它们。

  • Use no pool and open/close connections freely. 不使用游泳池和自由打开/关闭连接。 This is terribly inefficient. 这非常低效。 Don't do it. 不要这样做。

  • Keep a connection per thread using thread local storage. 使用线程本地存储保持每个线程的连接。 This'll work, but it's grossly inefficient because each open connection ties up database server resources while it sits idle. 这样做可行,但效率极低,因为每个开放连接在空闲时占用数据库服务器资源。 Don't do this unless you use an external connection pool like PgBouncer in transaction pooling mode, in which case it's OK. 除非您在事务池模式下使用像PgBouncer这样的外部连接池,否则不要这样做,在这种情况下它没关系。

  • Use only a single connection and wrap transactions in synchronized blocks, synchronizing on the Connection instance. 仅使用单个连接并在synchronized块中包装事务,在Connection实例上进行同步。 This'll work and will use the database connection efficiently but will limit your threads' performance. 这将有效并将有效地使用数据库连接,但会限制线程的性能。 It's generally not a good design for anything except toy/convenience apps. 除了玩具/便利应用之外,它通常不是一个好的设计。

  • Use only a single connection with its own dedicated thread. 仅使用具有自己专用线程的单个连接。 Have other connections pass data structures describing work to be done to that thread via a FIFO queue, producer/consumer style. 是否有其他连接通过FIFO队列,生产者/消费者样式传递描述要对该线程完成的工作的数据结构。 This works if the threads spend most of their time doing CPU-heavy or other non-database work and need only limited database access. 如果线程花费大部分时间来处理CPU繁重或其他非数据库工作并且仅需要有限的数据库访问,则此方法可行。 Pretty much the only reason to use it instead of using a connection pool is if you're constrained to using a single connection for some external reason, but if you are then it can be a decent option. 使用它而不是使用连接池的唯一原因是,如果由于某些外部原因而限制使用单个连接,但如果你是,那么它可能是一个不错的选择。

In general, though, you should just use a connection pool and be done with it. 但是,一般情况下,您应该只使用连接池并完成它。

Am I right in assuming that any attempt to use SQL transactions ( BEGIN and COMMIT style) is only going to be very confusing and broken, given the potential for the Java threads to interleave? 我是否正确地假设任何使用SQL事务( BEGINCOMMIT样式)的尝试只会非常混乱和破坏,因为Java线程可能会交错?

This is absolutely right. 这是绝对正确的。

Does the Connection object 'know' which Java thread is using it to make queries? Connection对象是否“知道”哪个Java线程正在使用它来进行查询?

No, it does not. 不,不是的。

Should I have one Connection object per Java thread and use the SQL transactions that way? 我应该为每个Java线程都有一个Connection对象并以这种方式使用SQL事务吗?

Yes, this is one way of doing it. 是的,这是一种做法。 The downside to the "connection per thread" allocation is a potential to open more connections than you need, leading to sub-optimal use of resources. “每线程连接”分配的缺点是可能会打开比您需要的更多连接,从而导致资源的次优使用。 You can also open a connection only when the thread needs it, and close it once thread is done with the RDBMS access. 您也可以仅在线程需要时打开连接,并在线程完成RDBMS访问后关闭它。 If you go this route, make sure that you use a connection pool to reduce the overhead of re-opening connections multiple times. 如果您使用此路由,请确保使用连接池以减少多次重新打开连接的开销。

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

No, connection object does not know which java thread is using it. 不,连接对象不知道哪个java线程正在使用它。

Should I have one Connection object per Java thread and use the SQL transactions that way? 我应该为每个Java线程都有一个Connection对象并以这种方式使用SQL事务吗? Or should I perform all my transactional isolation in the Java using synchronized? 或者我应该使用synchronized在Java中执行所有事务隔离?

We should use Database specific jdbc connection pool datasource to do transaction, so that when a connection object is of no use, then the connection will go back to the pool without being garbage collected. 我们应该使用特定于数据库的jdbc连接池数据源来执行事务,这样当连接对象没有用时,连接将返回池而不进行垃圾回收。 In that way, the application server can optimize it's connection initialisation performance. 通过这种方式,应用程序服务器可以优化其连接初始化性能。

Also, you should use synchronised method call during Update Operation because that will make much safer operation in production. 此外,您应该在更新操作期间使用同步方法调用,因为这将在生产中进行更安全的操作。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM