我们正在使用C#SqlCommand.ExecuteReader()
在事务中发出SQL Server存储过程和SQL请求。
当连接被选为死锁牺牲品时,ExecuteReader()
不会为某些命令抛出SqlException
1205死锁代码,但为其他命令执行操作。
根据MSDN
如果事务处于死锁状态,则在调用Read之前可能不会抛出异常。
考虑到我们使用封装在我们自己的数据库请求框架中的SqlCommand
对象,是否有办法始终保证在发生死锁时抛出异常?
我们正在使用.Net 4.5,SQL Server 2008 R2,Visual Studio 2012
以下是我们的数据库访问框架代码的简化版本:
SqlDataReader DoWork( string sql ) {
...
cmd = new SqlCommand( sql );
SqlDataReader rdr = null;
try {
rdr = cmd.ExecuteReader( CommandBehavior.Default );
} catch (SqlException sqle) {
// Log the error, throw a custom exception, etc.
// if (sqle.ErrorCode == 1205) ...
...
if (rdr != null) {
rdr.Close();
rdr = null;
}
}
// All is well, so just return to caller to consume the result set
return rdr;
}
...
main() {
...
SqlDataReader result = DoWork( "select ...";
if (result.HasRows) { // Check there is data to read...
while (result.Read()) {
...
}
result.Close();
...
}
答案 0 :(得分:3)
我不知道你为什么要这样做:
if (result.HasRows)
这不是必需的,它可以防止出现死锁:
如果事务处于死锁状态,则在调用Read之前可能不会抛出异常。
删除if
。这是一种常见的反模式。它通常是由那些复制示例代码的人引入的,而不是真正理解它的作用。
这在你的catch
中也是一种反模式:
if (rdr != null) {
rdr.Close();
rdr = null;
}
只需使用using
。
答案 1 :(得分:0)
这是该链接的代码,Stack不允许它作为答案
function DoWork() {
using (TransactionScope scope = new TransactionScope(...)) {
cmd = new SqlCommand("select ...");
using (DataReader rdr = cmd.ExecuteReader ()) {
while(rdr.Read()) {
... process each record
}
}
scope.Complete ();
}
}