JDBC - 用于只读操作的setAutoCommit

时间:2010-09-25 14:53:12

标签: java jdbc connection

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

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

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

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

4 个答案:

答案 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。

,请不要认为您的交易没有受到惩罚

<强>会展

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

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

  • 保持自动提交的默认JDBC行为;
  • 当您的函数包含多个SQL语句时,请在每个函数的开头设置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语句的(非常边际的)固定开销,以确保维护应用程序的数据完整性和稳定性。