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

Sql 我应该提交还是回滚读取事务?,sql,database,transactions,Sql,Database,Transactions,我有一个在事务中执行的读取查询,以便指定隔离级别。查询完成后,我应该怎么做 提交事务 回滚事务 不执行任何操作(这将导致事务在使用块结束时回滚) 每种方法的含义是什么 using (IDbConnection connection = ConnectionFactory.CreateConnection()) { using (IDbTransaction transaction = connection.BeginTransaction(IsolationLevel.ReadUnc

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

  • 提交事务
  • 回滚事务
  • 不执行任何操作(这将导致事务在使用块结束时回滚)
每种方法的含义是什么

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?
    }
}

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

如果读取不会改变状态,我将什么也不做。执行提交除了浪费一个向数据库发送请求的周期外,什么都不会做。您尚未执行已更改状态的操作。回滚也是如此


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

是否需要阻止其他人读取相同的数据?为什么要使用事务

@Joel-我的问题最好用“为什么在读取查询中使用事务?”

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

SELECT * FROM SomeTable WITH (NOLOCK)
EDIT@Comment 3:因为问题标签中有“sqlserver”,所以我假设MSSQLServer是目标产品。现在,这一点已经澄清,我已经编辑了标签,以删除特定的产品参考


我仍然不知道为什么您首先要在read op上进行事务处理

只是一个旁注,但您也可以这样编写代码:

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的using块移到顶部。

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

在您的代码示例中

  • //做些有用的事

    您正在执行更改数据的SQL语句吗

  • 如果不是,就没有“读取”事务。。。事务中只有Insert、Update和Delete语句(可以更改数据的语句)中的更改。。。您所说的是SQL Server对正在读取的数据加上的锁,因为其他事务会影响该数据。这些锁的级别取决于SQL Server隔离级别

    但是,如果SQL语句没有更改任何内容,则不能提交或回滚任何内容

    如果您正在更改数据,则可以更改隔离级别,而无需显式启动事务。。。每个SQL语句都隐式地存在于事务中。只有在确保同一事务中有两个或多个语句时,才需要显式启动事务

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


    注意:如果您正在执行多个read语句,并且希望它们都“看到”与第一个语句相同的数据库状态,则需要将隔离级别设置为top Repeatable read或Serializable…

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

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

    set transaction isolation level read uncommitted
    

    那么你就不必在C代码中跳过任何障碍。在存储过程中设置事务隔离级别不会导致该设置应用于该连接的所有未来使用(这是由于连接是池化的,所以您必须担心的问题)。在存储过程结束时,它只返回到初始化连接时使用的任何连接。

    您可以提交。时期没有其他明智的选择。如果您启动了一个事务,您应该关闭它。提交将释放您可能拥有的所有锁,并且对于ReadUncommitted或Serializable隔离级别同样敏感。依赖隐式回滚(虽然在技术上可能是等效的)只是一种糟糕的形式


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

    INSERT <代码>。例如,在标记为只读的事务中,Oracle驱动程序将完全避免查询中的表锁,这将在大量读取驱动的应用程序上获得大量性能。

    回滚主要用于出现错误或异常情况时,以及在成功完成时提交

    我们应该使用COMMIT(成功)和ROLLBACK(失败)关闭事务,即使在只读事务中,这似乎并不重要。事实上,对于一致性和未来证明,这确实很重要

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

    • 查询不会重新启动