我应该提交还是回滚读取事务?

时间:2008-11-21 19:10:27

标签: sql database transactions

我有一个在事务中执行的读取查询,以便我可以指定隔离级别。查询完成后,我该怎么办?

  • 提交交易
  • 回滚交易
  • 什么都不做(这将导致事务在使用块结束时回滚)

每个人都有什么影响?

using (IDbConnection connection = ConnectionFactory.CreateConnection())
{
    using (IDbTransaction transaction = connection.BeginTransaction(IsolationLevel.ReadUncommitted))
    {
        using (IDbCommand command = connection.CreateCommand())
        {
            command.Transaction = transaction;
            command.CommandText = "SELECT * FROM SomeTable";
            using (IDataReader reader = command.ExecuteReader())
            {
                // Read the results
            }
        }

        // To commit, or not to commit?
    }
}

编辑:问题不在于是否应该使用交易或是否有其他方式来设置交易级别。问题是,是否提交或回滚了不修改任何内容的事务。有性能差异吗?它会影响其他连接吗?还有其他差异吗?

12 个答案:

答案 0 :(得分:50)

你承诺。期。没有其他合理的选择。如果您开始了交易,则应该关闭它。提交释放您可能拥有的任何锁,并且对ReadUncommitted或Serializable隔离级别同样敏感。依靠隐式回滚 - 虽然技术上可能等同 - 只是表现不佳。

如果这还没有让你信服,那么想象下一个在代码中间插入更新语句的人,并且必须追踪发生的隐式回滚并删除他的数据。

答案 1 :(得分:25)

如果您没有更改任何内容,则可以使用COMMIT或ROLLBACK。任何一个都会释放你已经获得的任何读锁定,并且由于你没有做任何其他更改,它们将是等效的。

答案 2 :(得分:6)

如果您开始交易,那么最佳做法始终是提交。如果在您的使用(事务)块中抛出异常,则事务将自动回滚。

答案 3 :(得分:3)

恕我直言,在事务中包装只读查询是有意义的(特别是在Java中)你可以告诉事务是“只读”,反过来JDBC驱动程序可以考虑优化查询(但不必,所以没有人会阻止你发出INSERT。例如。 Oracle驱动程序将完全避免在标记为只读的事务中对查询进行表锁定,从而在大量读取驱动的应用程序上获得大量性能。

答案 4 :(得分:3)

考虑嵌套交易

大多数RDBMS不支持嵌套事务,或者尝试以非常有限的方式模拟它们。

例如,在MS SQL Server中,内部事务中的回滚(这不是真正的事务,MS SQL Server只计算事务级别!)将回滚 outmost 交易(这是真正的交易)。

某些数据库包装器可能会将内部事务中的回滚视为发生错误的标志,并在最外层事务中回滚所有内容,无论最外层事务是提交还是回滚。

因此,当您不能排除某个软件模块使用您的组件时,COMMIT是安全的方法。

请注意,这是对该问题的一般答案。通过打开新的数据库连接,代码示例巧妙地解决了外部事务的问题。

关于性能:根据隔离级别,SELECT可能需要不同程度的LOCK和临时数据(快照)。交易结束时清理。这是通过COMMIT还是ROLLBACK完成并不重要。花费的CPU时间可能没有显着差异 - COMMIT可能比ROLLBACK(两个字符更少)和其他微小差异更快解析。显然,这只适用于只读操作!

完全没有要求:另一个可能会阅读代码的程序员可能会认为ROLLBACK意味着错误情况。

答案 5 :(得分:2)

只是旁注,但你也可以写下这样的代码:

using (IDbConnection connection = ConnectionFactory.CreateConnection())
using (IDbTransaction transaction = connection.BeginTransaction(IsolationLevel.ReadUncommitted))
using (IDbCommand command = connection.CreateCommand())
{
    command.Transaction = transaction;
    command.CommandText = "SELECT * FROM SomeTable";
    using (IDataReader reader = command.ExecuteReader())
    {
        // Do something useful
    }
    // To commit, or not to commit?
}

如果你稍微重新构建一些东西,你也可以将IDataReader的使用块移动到顶部。

答案 6 :(得分:1)

如果将SQL放入存储过程并将其添加到查询上方:

set transaction isolation level read uncommitted

然后你不必跳过C#代码中的任何环节。在存储过程中设置事务隔离级别不会导致该设置适用于该连接的所有将来使用(由于连接已合并,因此您必须担心其他设置)。在存储过程结束时,它只会返回到初始化连接的任何内容。

答案 7 :(得分:1)

ROLLBACK主要用于出现错误或异常情况,并在成功完成时使用COMMIT。

我们应该使用COMMIT(成功)和ROLLBACK(失败)来关闭事务,即使在只读事务中它似乎并不重要。事实上,为了保持一致性和面向未来,它确实很重要。

只读事务在很多方面可以逻辑上“失败”,例如:

  • 查询未按预期返回一行
  • 存储过程引发异常
  • 发现的数据不一致
  • 用户因为时间过长而中止交易
  • 死锁或超时

如果COMMENT和ROLLBACK正确用于只读事务,如果在某个时刻添加了DB写代码,它将继续按预期工作,例如,用于缓存,审核或统计。

隐式ROLLBACK只应用于“致命错误”情况,当应用程序因不可恢复的错误,网络故障,电源故障等而崩溃或退出时

答案 8 :(得分:0)

鉴于READ不会改变状态,我什么都不做。执行提交将不会执行任何操作,除非浪费一个周期将请求发送到数据库。您尚未执行已更改状态的操作。同样适用于回滚。

但是,您应该确保清理对象并关闭与数据库的连接。如果重复调用此代码,则不关闭连接可能会导致问题。

答案 9 :(得分:0)

If you set AutoCommit false, then YES.

In an experiment with JDBC(Postgresql driver), I found that if select query breaks(because of timeout), then you can not initiate new select query unless you rollback.

答案 10 :(得分:-2)

在您的代码示例中,您有

  1. //做一些有用的事情

    您是否正在执行更改数据的SQL语句?

  2. 如果没有,就没有“读取”事务......只有来自插入,更新和删除语句的更改(可以更改数据的语句)才会在事务中...您所说的是由于影响该数据的OTHER事务,SQL Server会对您正在读取的数据进行锁定。这些锁的级别取决于SQL Server隔离级别。

    但是,如果您的SQL语句没有改变任何内容,则无法提交或返回任何内容。

    如果要更改数据,则可以在不明确启动转换的情况下更改隔离级别...每个单独的SQL语句都隐含在事务中。显式启动事务只需要确保2个或更多语句在同一个事务中。

    如果您只想设置事务隔离级别,那么只需将命令的CommandText设置为“Set Transaction Isolation level Repeatable Read”(或您想要的任何级别),将CommandType设置为CommandType.Text,然后执行命令。 (您可以使用Command.ExecuteNonQuery())

    注意:如果您正在执行MULTIPLE读取语句,并希望它们都“看到”与第一个相同的数据库状态,那么您需要设置隔离级别top可重复读取或可序列化...

答案 11 :(得分:-3)

您是否需要阻止他人阅读相同的数据?为什么要使用交易?

@Joel - 我的问题会更好地表达为“为什么在阅读查询中使用交易?”

@Stefan - 如果您要使用AdHoc SQL而不是存储过程,则只需在查询中的表之后添加WITH(NOLOCK)。这样,您不会在应用程序和事务数据库中产生开销(尽管很小)。

SELECT * FROM SomeTable WITH (NOLOCK)

编辑@评论3:由于问号标签中有“sqlserver”,我假设MSSQLServer是目标产品。现在已经澄清了这一点,我已经编辑了标签以删除特定的产品参考。

我仍然不确定你为什么要首先在read op上进行交易。