当 JDBC AutoCommit 为 False 且未设置显式事务边界时会发生啥

Posted

技术标签:

【中文标题】当 JDBC AutoCommit 为 False 且未设置显式事务边界时会发生啥【英文标题】:What happens when JDBC AutoCommit is False and explicit Transaction boundaries aren't set当 JDBC AutoCommit 为 False 且未设置显式事务边界时会发生什么 【发布时间】:2015-07-06 21:23:31 【问题描述】:

假设一个 Java 应用程序正在打开 JDBC 连接到 Postgres,AutoCommit 设置为 false。

在这样的 JDBC 连接上,如果我们执行 SQL SELECT 命令,那么事务边界会发生什么?即使 AutoCommit 已关闭,是否存在任何隐含事务边界?

【问题讨论】:

【参考方案1】:

6ton 是对的,这个答案应该被接受。我只是想详细说明一下。

您的应用程序将留下空闲的未处理事务。这可以防止一些清理工作,因为 PostgreSQL 无法将事务标记为最终提交或回滚。不做任何写操作也没关系(因为没有分配事务ID),但仍应避免。

如果您选择一个有副作用的函数,这些副作用将不会被提交,并且会在您断开连接时丢失。

如果您由于配置、数据库设置或用户默认设置而使用SERIALIZABLE 隔离,您将看到在第一个SELECT 拍摄的快照中的数据。由于无法VACUUM 删除旧行而导致的膨胀,您还会遇到数据库性能问题。这不会发生在 READ COMMITTED 隔离中。

您确实应该正确地执行此操作,并且自动提交或使用显式事务划分。

【讨论】:

只是为了确认:如果我将 autoCommit 设置为 False 并且我不需要明确的事务划分,那么当第一个 SELECT(或 UPDATE/INSERT/DATE)为执行了吗? @Mecon By PgJDBC 实际上但是是的。并且从未提交,因此插入/更新/删除的数据将被丢弃。当然,除非您发出提交请求。不提交就断开连接 = 回滚。 当我在长时间运行的 SELECT 期间遇到异常时,连接处于错误状态.. 并且该连接上的后续 SELECT 会给出有关“在事务结束之前的所有命令都将被忽略”的错误消息。 ..我没有捕获其他消息,但它表明我需要回滚事务,因为发生了异常。 @Mecon 是的。这是正常的。有什么问题?发生错误后,事务处于无效状态,您必须回滚才能继续工作。也许您应该打开自动提交或使用显式事务管理? 我不能(也不会)打开自动提交,因为许多其他现有代码依赖于事务边界。我必须设置 Transaciton 边界,但是有很多代码没有设置它们。【参考方案2】:

自动提交不会有任何效果,因为您只是触发选择。

默认事务隔离级别将对 select 子句起作用 - 对于 postgres,它设置为 READ_COMMITTED。来自docs:

Read Committed 是 PostgreSQL 中的默认隔离级别。当一个 事务使用这个隔离级别,一个 SELECT 查询(没有 FOR UPDATE/SHARE 子句)只看到查询开始前提交的数据; 它永远不会看到未提交的数据或期间提交的更改 通过并发事务执行查询。

【讨论】:

感谢您的回答,但我想我遇到了没有事务边界和自动提交错误的问题,当异常发生时会导致错误的连接实例。所以即使我只做 SELECTs .. Postgres 的一些“隐含的”与事务相关的活动导致我有一些意外的连接状态。 有异常吗?如果您发布堆栈跟踪会有所帮助

以上是关于当 JDBC AutoCommit 为 False 且未设置显式事务边界时会发生啥的主要内容,如果未能解决你的问题,请参考以下文章

如何在spring jdbc模板中将自动提交设置为false

JDBC——事物管理

为什么在Hibernate中不建议使用“hibernate.connection.autocommit = true”?

当MYSQL设置AUTOCOMMIT = 0时,Mybatis sqlSession.com不起作用

明明已经设置了setAutoCommit(false);为啥还是报错AutoCommit 模式设置为"true"时,无法调用回滚操作.

使用带有 autocommit=true 的 jdbc 时回滚批处理执行