假设我有一个创建数据库连接的常用方法:
Connection getConnection() throws SQLException {
Connection con = ... // create the connection
con.setAutoCommit(false);
return con;
}
我将setAutoCommit(false)
调用放在这里,以便此方法的调用者永远不必担心设置它。但是,如果调用者执行的操作只是读取数据,这是不好的做法吗?有没有额外的开销?
我个人认为最好将逻辑集中在一个地方,这样调用者就不必设置自动提交,这样可以避免代码冗余。我只是想确保它不会给只读操作带来任何不必要的开销。
答案 0 :(得分:5)
自动提交对SELECT
个查询没有任何价值。但是,关闭自动提交确实是一种更常见的做法。通常,您希望在事务中触发查询。默认情况下,大多数连接池也将其关闭。但是我建议将它作为连接管理器的配置设置和/或使用布尔参数重载方法,这样你至少可以对它进行任何控制。
答案 1 :(得分:5)
我在这里调用setAutoCommit(false)调用,以便此方法的调用者不必担心设置它。
这是很好的IMO,我个人认为永远不应该在应用程序中启用自动提交模式。所以我的建议是关闭自动提交。
但是,如果调用者执行的操作只是读取数据,这是不好的做法吗?有没有额外的开销?
从严格的性能角度来看,它为每个具有开销的SQL语句开始和结束数据库事务,并可能降低应用程序的性能。
顺便说一句,根据javadoc:
,SELECT语句受setAutoCommit(boolean)
的影响
设置此连接的自动提交 模式到给定状态。 如果是 连接处于自动提交模式, 然后它的所有SQL语句都将是 作为个人执行和承诺 交易即可。否则,它的SQL 语句分为 由a终止的交易 调用方法commit或 方法回滚。默认情况下,新的 连接处于自动提交模式。
语句时发生提交 完成。声明的时间 完成取决于SQL的类型 语句:
- 对于DML语句,例如Insert,Update或Delete,以及DDL语句, 声明尽快完成 它已经完成了执行。
- 对于Select语句,语句在关联结果时完成 设置已关闭。
- 对于CallableStatement对象或返回多个的语句 结果,声明完整 当所有相关的结果集 已关闭,所有更新 计数和输出参数已经 检索。
答案 2 :(得分:3)
这是一个老问题,但我想就此问题给出不同意见。
<强>性能强>
事务的性能开销因并发控制机制而异:通常是多版本并发控制或锁定。其他答案中表达的担忧似乎取决于结束交易的成本,但根据我的经验,最大的痛苦是长期交易,这可能会导致性能瓶颈。例如,如果DBMS使用锁定,则在涉及该表的事务终止之前,不能更新表的某些部分。在诸如Oracle之类的系统中更令人沮丧的是,DDL操作(ALTER TABLE
等)必须等到使用该表的所有事务都结束,从而导致麻烦的超时。因此,如果您只使用SELECT
s。
<强>会展强>
设置自动提交行为的一个微妙问题是您正在更改默认设置,因此使用您的代码的任何其他人可能都不会期望它。通过函数留下意外路径非常容易而不是以明确的commit
或rollback
结束,这可能导致后续调用函数中的不可预测行为。相反,我看到的很大一部分DB接口代码在每个函数中都包含一个语句,因此自动提交行为非常适合。事实上,我遇到的许多多语句函数可能已经被重新编写为具有更多SQL专有技术的单个语句 - 在Java中实现的连接的不良近似很可能很常见。
根据合理的经验,我个人偏好对于调用数据库的任何函数都如下:
setAutocommit(false)
并在结束时调用commit()
(或rollback()
,如果适用),使用显式事务,理想情况下rollback()
块中的catch
; setAutocommit(true)
放入函数中包含JDBC调用的finally
块来强制执行默认值(与PHP / PDO之类的API不同,JDBC在{{1}之后不会为您执行此操作}} / commit()
); rollback()
或setAutocommit(true)
的选择; 答案 3 :(得分:1)
我永远不会在应用程序的任何地方将autoCommit设置为true。
如果有的话,性能开销与侧面相比毫无结果
autocommit=true
连接的影响。
您说永远不会将此连接用于DML。但这就是意图,可能是由编码标准等维护的。但在实践中, 可以将此连接用于DML语句。这足以让我永远不会设置自动提交。
Select
语句肯定会占用一些内存/ CPU /网络。让自动提交的开销成为每个select语句的(非常边际的)固定开销,以确保维护应用程序的数据完整性和稳定性。