我正在使用 JDBC 与我的 Postgres 数据库通信。如果我的整个应用程序都在一个连接上运行,即只有一次调用;
DriverManager.getConnection("jdbc:postgresql://host:5432/database", user, pass);
但是这个 Connection
对象在 Java 中跨多个线程共享,我假设任何尝试使用 SQL 事务(BEGIN
和 COMMIT
style) 考虑到 Java 线程交错的可能性,只会变得非常困惑和损坏? Connection
对象是否“知道”哪个 Java 线程正在使用它进行查询?
我是否应该为每个 Java 线程创建一个 Connection
对象并以这种方式使用 SQL 事务?或者我应该使用 synchronized
在 Java 中执行所有事务隔离吗?
最佳答案
只是详细说明现有的答案:
PgJDBC's Connection
object is thread-safe ,但仅限于语句级别。当在自动提交模式下被多个线程使用时,它不会崩溃或产生错误结果,但它不会为您隔离不同线程的事务。根据文档,您需要为此使用连接池。
实际上有很多方法可以在多线程之间使用连接:
使用内部连接池,您可以从中获取连接、使用它们执行工作并将它们返回到池中。对于大多数应用程序来说,这是非常可取的选择。 Java 存在许多 JDBC 连接池实现,所以不要自己动手。 dbcp和 c3p0是两种流行的实现方式,但如果您使用的是 servlet 环境或应用服务器,您通常应该使用服务器的连接池,而不是自带。
使用 pgbouncer 或 pgpool-II 等外部连接池,并自由打开/关闭与它的连接。这稍微慢一些,主要用于应用程序不能或出于各种原因不应在内部池化连接的情况。您可能不需要这样做,除非您需要限制数据库的总连接数并在多个应用程序或应用程序实例之间共享它们。
不使用池并自由打开/关闭连接。这是非常低效的。不要这样做。
使用线程本地存储为每个线程保持一个连接。这会起作用,但效率非常低,因为每个打开的连接在空闲时都会占用数据库服务器资源。不要这样做,除非你在事务池模式下使用像 PgBouncer 这样的外部连接池,在这种情况下是可以的。
仅使用单个连接并将事务包装在
synchronized
block 中,在Connection
实例上同步。这将有效并有效地使用数据库连接,但会限制线程的性能。对于玩具/便利应用程序以外的任何东西,它通常都不是一个好的设计。仅使用具有自己的专用线程的单个连接。让其他连接通过 FIFO 队列、生产者/消费者样式将描述要完成的工作的数据结构传递给该线程。如果线程将大部分时间用于 CPU 密集型工作或其他非数据库工作并且只需要有限的数据库访问,则此方法有效。使用它而不是使用连接池的唯一原因几乎是如果您出于某些外部原因而不得不使用单个连接,但如果您是,那么它可能是一个不错的选择。
不过,一般来说,您应该只使用连接池并完成它。
关于java - JDBC 事务与连接说明,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15642218/