5

说明我的问题的最简单方法是使用以下 C# 代码:

using (SqlCommand cmd = new SqlCommand("SELECT * FROM [tbl]", connectionString))
{
    using (SqlDataReader rdr = cmd.ExecuteReader())
    {
        //Somewhere at this point a concurrent thread, 
        //or another process changes the [tbl] table data

        //Begin reading
        while (rdr.Read())
        {
            //Process the data
        }
    }
}

那么rdr在这种情况下,数据会怎样呢?

4

1 回答 1

4

我实际上对此进行了测试。测试代码:

using (SqlConnection conn = new SqlConnection(ConfigurationManager.ConnectionStrings["test"].ConnectionString))
{
    conn.Open();
    using (SqlCommand comm = new SqlCommand("select * from test", conn))
    {
        using (var reader = comm.ExecuteReader())
        {
            int i = 0;
            while (reader.Read())
            {
                if ((string)reader[1] == "stop")
                {
                    throw new Exception("Stop was found");
                }
            }
        }
    }
}

为了测试,我用一些虚拟数据初始化了表(确保没有包含值为“stop”的行)。然后我在行上放了一个断点int i = 0;。当执行在断点处停止时,我在表中插入了一行带有“停止”值的行。

结果是,根据表中初始行的数量,Exception抛出/未抛出。我没有试图确定行限制的确切位置。对于十行,Exception没有抛出,这意味着读者没有注意到从另一个进程添加的行。一万行,抛出异常。

所以答案是:视情况而。如果不将命令/阅读器包装在 aTransaction中,则不能依赖任何一种行为。

强制性免责声明:这就是它在我的环境中的工作方式......

编辑:

我在我的开发机器上使用本地 Sql 服务器进行了测试。它报告自己为:

微软 SQL Server 2008 R2 (SP1) - 10.50.2550.0 (X64)

关于交易:

这是我使用事务的代码:

using (SqlConnection conn = new SqlConnection(ConfigurationManager.ConnectionStrings["test"].ConnectionString))
{
    conn.Open();
    using (var trans = conn.BeginTransaction())
    using (SqlCommand comm = new SqlCommand("select * from test", conn, trans))
    {
        using (var reader = comm.ExecuteReader())
        {
            int i = 0;
            while (reader.Read())
            {
                i++;
                if ((string)reader[1] == "stop")
                {
                    throw new Exception("Stop was found");
                }
            }
        }
        trans.Commit();
    }
}

在这段代码中,我在没有明确指定隔离级别的情况下创建了事务。这通常意味着System.Data.IsolationLevel.ReadCommitted将被使用(我认为可以在某处的 Sql Server 设置中设置默认隔离级别)。在这种情况下,阅读器的行为与以前相同。如果我将其更改为使用:

...
using (var trans = conn.BeginTransaction(System.Data.IsolationLevel.Serializable))
...

“停止”记录的插入被阻塞,直到事务被提交。这意味着当阅读器处于活动状态时,Sql Server 不允许对底层数据进行任何更改。

于 2013-06-26T12:11:05.633 回答