SqlDataReader.Read和大记录

时间:2016-08-29 09:49:58

标签: c# sql-server-2012 sqldatareader

当结果集包含一个大列时,使用SqlDataReader.Read()时会出现一些奇怪的行为。

会发生什么:

  • 未读取整个记录
  • 在阅读器和连接关闭后,记录仍然处于锁定状态。

除非我在大列上明确调用reader.Get*

这是一些显示我的意思的测试代码。

CREATE TABLE TestXml (
    Id int NOT NULL
   ,number int NOT NULL
   ,data xml NOT NULL
);

INSERT INTO TestXml
VALUES (1, 0, (SELECT TOP 100 * FROM sys.objects FOR XML PATH('Objects')))
      ,(2, 0, (SELECT TOP 1000 * FROM sys.objects FOR XML PATH('Objects')))
      ,(3, 0, (SELECT TOP 10000 a.* FROM sys.objects a, sys.objects b FOR XML PATH('Objects')))

获取数据的代码

const int TestId = 1;

using (var connection1 = new SqlConnection(ConnectionString))
using (var connection2 = new SqlConnection(ConnectionString))
using (var command1 = new SqlCommand())
using (var command2 = new SqlCommand()) {
    command1.Connection = connection1;
    command1.CommandText =
        "SELECT Id, number, data " +
        "FROM TestXml " +
        "WHERE Id = @Id";

    command2.Connection = connection2;
    command2.CommandText = 
        "UPDATE TestXml " + 
        "SET number = number + 1 " +
        "WHERE Id = @Id";

    connection1.Open();
    connection2.Open();

    command1.Parameters.Add("@Id", SqlDbType.Int).Value = TestId;
    using (var reader = command1.ExecuteReader()) {
        if (reader.Read()) {
            var id = reader.GetInt32(0);

            //// reader.GetValue(2);
            command2.Parameters.Add("@Id", SqlDbType.Int).Value = id;
            command2.ExecuteNonQuery();
        }
    }
}

当Id = 1或2 =>更新工作正常。
当Id = 3 =>超时异常。

如果我取消注释reader.GetValue(2),Id = 3也能正常工作。

这是读者的预期行为吗? 不能关闭阅读器取消查询并释放锁吗?

我知道我可以使用CommandBehavior.SequentialAccess来传输结果,但在这种情况下,没有计划大对象。

修改:只是为了表明您不需要更新,以便在阅读器关闭后保持锁定状态。任何异常都会关闭阅读器,但会锁定记录,例如

using (var connection1 = new SqlConnection(ConnectionString))
using (var command1 = new SqlCommand())
    command1.Connection = connection1;
    command1.CommandText =
        "SELECT Id, number, data " +
        "FROM TestXml " +
        "WHERE Id = 3";

    connection1.Open();

    using (var reader = command1.ExecuteReader()) {
        if (reader.Read()) {
            var id = reader.GetInt32(0);
            throw new Exception("whatever");
        }
    }
}

(第3行仍然被锁定)

0 个答案:

没有答案