当结果集包含一个大列时,使用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行仍然被锁定)