为什么SqlCommand.ExecuteReader()在收到锁定超时错误时抛出异常?

时间:2014-07-23 17:54:02

标签: c# .net sql-server timeout locking

我有一个标识列为FOO的表ID。在事务中,我使用id 1锁定行。

如果我在另一个事务中在SQL Server Management Studio中尝试这一行SQL:

select * from FOO with (updlock, rowlock, nowait) where ID = 1

...我收到此错误:

Msg 1222, Level 16, State 51, Line 1
Lock request time out period exceeded.

哪个好,因为那就是所谓的发生的事情。

我有这个测试代码(省略错误处理):

internal class Constants
{
    public const string CONNECT = @"Data Source=.\TEST;Initial Catalog=TEST;User ID=YOURNAME;Password=" + "\"\"" + @";Integrated Security=SSPI;";
    public const string COMMAND = "select * from FOO with (updlock, rowlock, nowait) where ID = 1";
}

internal class Locker
{
    private SqlConnection _connect;
    private SqlTransaction _transact;

    public void Lock()
    {
        _connect = new SqlConnection(Constants.CONNECT);
        _connect.Open();
        _transact = _connect.BeginTransaction();

        using (var cmd = new SqlCommand(Constants.COMMAND, _connect, _transact))
        {
            using (var reader = cmd.ExecuteReader(CommandBehavior.SingleResult))
            {
                if (reader.HasRows)
                    reader.Read();
            }
        }
    }

    public void Unlock()
    {
        _transact.Rollback();
        _transact.Dispose();
        _connect.Close();
        _connect.Dispose();
    }
}

internal class Tester
{
    public int Test()
    {
        int count;
        using (var connect = new SqlConnection(Constants.CONNECT))
        {
            connect.Open();
            using (var transact = connect.BeginTransaction())
            {
                using (var cmd = new SqlCommand(Constants.COMMAND, connect, transact))
                {
                    try
                    {
                        using (var reader = cmd.ExecuteReader(CommandBehavior.SingleResult))
                        {
                            count = 0;
                            if (reader.HasRows)
                                while (reader.Read())
                                    count++;
                        }
                    }
                    catch (SqlException)
                    {
                        count = -1;
                    }
                }
                transact.Rollback();
            }
            connect.Close();
        }
        return count;
    }
}

如果我然后创建LockerTester并让测试人员在锁定器锁定时尝试选择该行,tester.Test()会返回 0

命令不应该抛出锁定超时异常,该方法会捕获&通过返回-1表示?如果没有,我如何区分“没有这样的行存在”和“该行存在但其他人将其锁定”之间的区别?为什么这在SSMS中工作正常但在C#中没有?

它的行为类似于提供READPAST table hint,但我们可以在代码中清楚地看到它不是。是否有任何方式可以在.NET库代码中以某种方式设置提示的行为?

注意:我已经尝试过使用储物柜和放大器的每种隔离级别组合。测试人员以及超时期限,而不是使用NOWAIT

0 个答案:

没有答案