【问题标题】:Should autocommit of a datasource be set to false?数据源的自动提交是否应该设置为 false?
【发布时间】:2016-04-04 06:29:59
【问题描述】:

请看spring DataSourceTransactionManager.java中的cmets,函数doBegin:

// Switch to manual commit if necessary. This is very expensive in some JDBC drivers,
// so we don't want to do it unnecessarily (for example if we've explicitly
// configured the connection pool to set it already).
        if (con.getAutoCommit()) {
            txObject.setMustRestoreAutoCommit(true);
            if (logger.isDebugEnabled()) {
                logger.debug("Switching JDBC Connection [" + con + "] to manual commit");
            }
            con.setAutoCommit(false);
        }

在我正在处理的项目中,未配置自动提交。所以默认情况下是真的。我们使用 Spring 来管理事务,所有 SQL 都在 @Transactional 注解的函数中执行。所以事务实际上是手动提交的。每次事务开始时,数据库连接都设置为 false,事务退出后自动提交设置回 true。一个典型的工作流程是(在 JDBC 级别):

  1. conn = dataSource.getConnection();
  2. conn.setAutoCommit(假);
  3. stmt = conn.createStatement();
  4. stmt.executeQuery(...);
  5. conn.commit()/conn.rollback();
  6. conn.setAutoCommit(true);

来回设置自动提交是否昂贵?出于性能原因,我们应该配置数据源连接池 autocommit=false 吗?跳过第 2 步和第 6 步。

【问题讨论】:

    标签: java mysql oracle transactions datasource


    【解决方案1】:

    在批量操作中,您可以在会话中将其关闭,并在批量操作完成后再次打开以提高性能。

    SET autocommit=0;
    your code here....
    SET autocommit=1;
    

    更新:

    正如@codemania 很好地解释的那样,即使可以根据您的要求禁用自动提交,但您不应该这样做。即使这是事务成功提交一组指令或回滚的基本需求,如果你禁用它,那么你将如何实现它。

    如果您正在执行一些大型任务(例如数据迁移等),这将很有用,因为您可以禁用自动提交以提高性能,但仅限于该会话。

    【讨论】:

      【解决方案2】:

      1) 自动提交完全依赖于数据库,这意味着通过连接的每一条语句都将在隐式执行的单独事务中执行。除非您想使用个人编码并避免这些锁被多个语句持有而导致与其他用户发生冲突,否则无需将自动提交设置为 false。

      2)从性能上看,

      a) 如果您有很多用户并且由于持有数据库锁而发生一些冲突, 那么,可能需要检查与之相关的问题,但作为一般 规则,引入自动提交是为了简化初学者的东西。

      b) 可能存在需要回滚的情况。

      c) 您想根据特定条件手动提交事务。

      编辑:我看到你已经编辑了这个问题,简单地回答你,autocommit=false 将强制你编写自己的提交/回滚/等,性能完全取决于数据库,同时持有的锁数实时!!

      没有。再次将 autocommit 设置为 false 和 true 不会增加系统开销。

      不,不要配置数据源连接池 autocommit=false,除非您出于某种特定原因这样做并且是有经验的人。从性能的角度来看,正如我已经标明的那样,它取决于数据库的类型和在实例中访问数据库的实时用户,对于您的项目,99.99% 您不需要将其设置为 false。

      将 autocommit 设置为 true 只会确保在每个语句之后调用 commit。

      我还看到您正在从数据源获取连接,在这种情况下,最好使用默认设置保留连接,以便下次从池中获取该连接时不会有任何问题与工作流程

      希望这有帮助!

      【讨论】:

      • 我猜这些设置自动提交命令将需要两次往返,并且在我的测试中为每个事务花费额外的 0.8 毫秒。
      • 从逻辑上讲,正如我所见,问题将在于在包含各种语句的事务结束后将 autocommit 设置为 true,因为您再次告诉系统返回默认状态并处理一切当您将自动提交设置为 false 时,情况并非如此,因此可能有 1 次往返而不是两次花费您 0.8milli 的费用,如果您只是关闭连接,那么事情还取决于您在 setautocommit 为 true 之后所做的事情,有什么关系? :D
      【解决方案3】:

      每当您发出数据库事务时,都应该将 autocommit 设置为 true。数据库事务是一个逻辑工作单元,它通常由多个数据库操作(通常是多个更新)组成,您希望它们全部成功或全部失败。使用 autocommit=false,您的更改将不会持久,直到您在连接对象上调用 commit(),因此这种方法保证您的所有更新要么成功要么失败(通过在异常情况下调用回滚等)。

      当自动提交设置为 true(默认值)时,例如,您可以更改一个表,但在第二次更新(无论是更新/插入还是删除)时,可能会发生异常并且您的第二个表不会'不更新,从而使您的数据库处于不一致的状态。

      总而言之,autocommit=true 在只读取数据或者数据库数据模型简单且用户很少访问的情况下是可以的(这样并发访问同一数据区域的情况非常罕见,甚至在某些数据库不一致的情况下)容忍)

      【讨论】:

        猜你喜欢
        • 2012-05-07
        • 1970-01-01
        • 1970-01-01
        • 2019-07-30
        • 1970-01-01
        • 2016-11-06
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多