如何在不复制存储过程代码的情况下提示更新锁定

时间:2011-08-08 13:56:45

标签: c# sql-server sql-server-2008 stored-procedures deadlock

我有一个现有的存储过程SP1,可以从表中进行简单的选择。它被用于多个地方。

现在有一个新代码在一个可序列化的事务中使用此SP1以及更新语句。我看到死锁,其中两个事务能够在同一组行上获取读锁定,现在想要将该锁定转换为更新。

一种可能的解决方案是使此SP1在读提交隔离级别执行。 但我认为这不是正确的解决方法,因为可能会丢失更新。另一个解决方案是在SP1的select语句中提示UPDLOCK。这将解决死锁,因为任何事务获取UPDLOCK只会继续。另一个事务必须等待提交。

现在向此SP1添加UPDLOCK不必要地为其他调用SP1但不希望UPDLOCK的地方增加此开销。因此,人们可能会认为要复制此SP1并使新的SP1UPDLOCK与SP1相同但使用UPDLOCK。我不希望这种重复。 那么调用者是否有任何方式可以提示无论SP1返回什么都应该使用UPDLOCK。

解决此类问题的任何其他更好方法。

我正在使用SQL Server 2008,C#,.NET 4。

示例代码

CREATE PROCEDURE SP1
    @SomeId int
AS
BEGIN
    Select Foo From Bar Where SomeOne = @SomeId
END

CREATE PROCEDURE SP1UPDLOCK
    @SomeId int
AS
BEGIN
    Select Foo From Bar (UPDLOCK) Where SomeOne = @SomeId
END

CREATE PROCEDURE SP2
    @Foo int
    @SomeId int
AS
BEGIN
    Update Bar
    Set Foo = @foo
    Where SomeOne = @someId
End

C#代码

Using(Transaction t = new Transaction())
{
    result = SP1(someId);
    // some logic here
    if(somecond == true)
    {
        SP2(fooVal, someId);
    }

    t.Commit();
}

1 个答案:

答案 0 :(得分:1)

如果SP2之后对SP1的调用是原子的,则它们应该在T-SQL中组合。 或者丢失c#事务。您通过往返不必要地延长了交易。

另外,为什么UPUPOCK在SP1UPDLOCK而不是SP1?我不明白为什么。如果问题是锁定提示,请不要使用它们。如果某些东西是可序列化的(为什么?)那么再次,使它成为一个原子调用

请注意,默认情况下是READ COMMITTED

最后,你的意思是“信号量”没有锁定?使用sp_getapplock将控制代码流,而不使用数据上的锁