死锁时,SqlCommand.ExecuteReader()不会抛出SqlException

时间:2015-08-28 20:25:37

标签: c# .net sql-server

我们正在使用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();
    ...
}

2 个答案:

答案 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 ();
 }
}
相关问题