使用 JDBC 处理事务的经典方法似乎是将自动提交设置为 false。这将创建一个新事务,并且每次调用 commit 都标志着下一个事务的开始。在多线程应用程序上,我知道为每个线程打开一个新连接是常见的做法。
我正在编写一个基于 RMI 的多客户端服务器应用程序,因此基本上我的服务器为每个新连接无缝地生成一个线程。为了正确处理事务,我应该为每个线程创建一个新连接吗?这种架构的成本是不是太高了?
使用 JDBC 处理事务的经典方法似乎是将自动提交设置为 false。这将创建一个新事务,并且每次调用 commit 都标志着下一个事务的开始。在多线程应用程序上,我知道为每个线程打开一个新连接是常见的做法。
我正在编写一个基于 RMI 的多客户端服务器应用程序,因此基本上我的服务器为每个新连接无缝地生成一个线程。为了正确处理事务,我应该为每个线程创建一个新连接吗?这种架构的成本是不是太高了?
是的,通常您需要为每个线程创建一个新连接。您无法控制操作系统如何对线程的执行进行时间切片(尽管定义了您自己的关键部分),因此您可能会无意中让多个线程尝试通过该管道发送数据。
请注意,这同样适用于任何网络通信。例如,如果您有两个线程试图通过 HTTP 连接共享一个套接字。
如果您将所有事务包装在关键部分中,因此在整个开始/提交周期中锁定任何其他线程,那么您可能能够在线程之间共享数据库连接。但即使那样我也不会这样做,除非你真的对 JDBC 协议有先天的了解。
如果您的大多数线程很少需要数据库连接(或根本不需要),您也许可以指定一个线程来完成您的数据库工作,并让其他线程将它们的请求排队到该线程。这将减少这么多连接的开销。但是你必须弄清楚如何在你的环境中管理每个线程的连接(或者在 StackOverflow 上询问另一个关于这个的具体问题)。
更新:要在评论中回答您的问题,大多数数据库品牌不支持单个连接上的多个并发事务(InterBase/Firebird 是我所知道的唯一例外)。
最好有一个单独的事务对象,并且能够在每个连接中启动和提交多个事务。但是供应商根本不支持它。
同样,标准的独立于供应商的 API(如 JDBC 和 ODBC)做出相同的假设,即事务状态仅仅是连接对象的一个属性。
为每个线程打开一个新连接是不常见的做法。通常你使用像c3po库这样的连接池。
如果您在应用程序服务器中,或者例如使用 Hibernate,请查看文档,您将了解如何配置连接池。
同一个连接对象可以用来创建多个语句对象,然后这些语句对象可以被不同的线程同时使用。大多数由 JDBC 连接的现代数据库都可以做到这一点。因此,JDBC 能够如下使用并发游标。PostgreSQL在这里也不例外,例如:
http://doc.postgresintl.com/jdbc/ch10.html
这允许连接池,其中连接只使用很短的时间,即创建语句对象,但之后返回池。仅当 JDBC 连接同时执行语句操作的并行化时才建议使用这种短时间池,否则正常的连接池可能会显示更好的结果。无论如何,线程可以继续使用语句对象并稍后关闭它,但不能关闭连接。
1. Thread 1 opens statement
3. Thread 2 opens statement
4. Thread 1 does something Thread 2 does something
5. ... ...
6. Thread 1 closes statement ...
7. Thread 2 closes statement
以上仅适用于自动提交模式。如果需要事务,则仍然不需要将事务绑定到线程。您可以将池划分为所有事务,并使用与上述相同的方法。但这不是因为某些套接字连接限制而是因为 JDBC 将会话 ID 等同于事务 ID 才需要这样做。
如果我没记错的话,应该有一些设计不那么简单的 API 和产品,其中会话 ID 和事务 ID 并不等同。在此 API 中,您可以使用单个数据库连接对象编写服务器,即使它执行事务也是如此。稍后需要检查并告诉您这些 API 和产品是什么。