JDBC – 用于只读操作的setAutoCommit

假设我有一个创建数据库连接的常用方法:

Connection getConnection() throws SQLException { Connection con = ... // create the connection con.setAutoCommit(false); return con; } 

我在这里setAutoCommit(false)调用,以便此方法的调用者不必担心设置它。 但是,如果调用者执行的操作只是读取数据,这是不好的做法吗? 有没有额外的开销?

我个人认为,最好将逻辑集中在一个地方,这样调用者就不必设置自动提交,这样可以避免代码冗余。 我只是想确保它不会给只读操作带来任何不必要的开销。

我在这里调用setAutoCommit(false)调用,以便此方法的调用者不必担心设置它。

这是很好的IMO,我个人认为永远不应该在应用程序中启用自动提交模式。 所以我的建议是关闭自动提交。

但是,如果调用者执行的操作只是读取数据,这是不好的做法吗? 有没有额外的开销?

从严格的性能角度来看,它为每个具有开销的SQL语句开始和结束数据库事务,并可能降低应用程序的性能。

顺便说一下,根据javadoc,SELECT语句受setAutoCommit(boolean)影响:

将此连接的自动提交模式设置为给定状态。 如果连接处于自动提交模式,则其所有SQL语句将作为单个事务执行并提交 。 否则,其SQL语句将分组为通过调用方法提交或方法回滚来终止的事务。 默认情况下,新连接处于自动提交模式。

语句完成时发生提交。 语句完成的时间取决于SQL语句的类型:

  • 对于DML语句,例如Insert,Update或Delete,以及DDL语句,语句在完成执行后立即完成。
  • 对于Select语句,关闭关联结果集时语句完成。
  • 对于CallableStatement对象或返回多个结果的语句,当关闭所有关联的结果集并且已检索到所有更新计数和输出参数时,语句将完成。

Autocommit对SELECT查询没有任何价值。 但是,关闭自动提交确实是一种更常见的做法。 通常,您希望在事务中触发查询。 默认情况下,大多数连接池也将其关闭。 但是我建议将它作为连接管理器的配置设置和/或重载带有布尔参数的方法,这样你至少可以对它进行任何控制。

这是一个老问题,但我想就这个问题给出不同意见。

性能

事务的性能开销因并发控制机制而异:通常是多版本并发控制或锁定。 在其他答案中表达的担忧似乎取决于结束交易的成本,但根据我的经验,最大的痛苦是长期运行的交易,这可能导致性能瓶颈。 例如,如果DBMS使用锁定,则在涉及该表的事务终止之前,不能更新表的某些部分。 在诸如Oracle之类的系统中更令人沮丧的是,DDL操作( ALTER TABLE等)必须等到使用该表的所有事务都结束,从而导致麻烦的超时。 因此,如果您只是使用SELECT请不要认为您的交易没有任何惩罚。

约定

设置自动提交行为的一个微妙问题是您正在更改默认设置,因此使用您的代码的任何其他人可能都不会期望它。 通过函数留下意外路径比不以显式commitrollback结束非常容易 ,这可能导致后续调用函数中的不可预测行为。 相反,我看到的很大一部分DB接口代码在每个函数中都包含一个语句,因此自动提交行为非常适合。 事实上,我遇到的很多多语句函数可能已经被重写为具有更多SQL专有技术的单个语句 – 在Java中实现的连接的差异近似很可能很常见。

根据合理的经验,我个人的偏好如下所示,对于调用数据库的任何函数:

  • 保持自动提交的默认JDBC行为;
  • 当你的函数包含多个SQL语句时,通过在每个函数的开头设置setAutocommit(false)并在setAutocommit(false)调用commit() (或者如果合适的话,使用rollback()使用显式事务,理想情况下是rollback() catch ;
  • 通过在函数中包装JDBC调用的finally块中放置setAutocommit(true)来强制执行默认值(与PHP / PDO之类的API不同,JDBC在commit() / rollback()之后不会为您执行此操作);
  • 如果你感觉额外的防御,在每个函数的开头明确设置你选择的setAutocommit(true)setAutocommit(false) ;

我永远不会在应用程序的任何地方将autoCommit设置为true。 与autocommit=true连接的副作用相比,任何情况下的性能开销都是autocommit=true

你说你永远不会将此连接用于DML。 但这是意图 ,可能通过编码标准等维护。但在实践中,可以将此连接用于DML语句。 这足以让我永远不会设置自动提交。

Select语句肯定会占用一些内存/ CPU /网络。 让autocommit的开销成为每个select语句的(非常边际的)固定开销,以确保维护应用程序的数据完整性和稳定性。