如何提示更新锁而不重复存储过程代码
我有一个现有的存储过程 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();
}
I've an existing stored procedure SP1 which is simple select from a table. It's being used at multiple places.
Now there is a new code which uses this SP1 along with an update statement in one serializable transaction. I'm seeing deadlock where two transactions are able to acquire read lock on same set of rows and now want to convert that lock to update.
One possible solution is to make this SP1 execute in read committed isolation level. But I think this is not the right fix, as there can be lost updates. Another solution is to hint UPDLOCK
in SP1's select statement. This will resolve the deadlock as whatever transaction acquires that UPDLOCK will only proceed. The other transaction will have to wait for this to commit.
Now adding UPDLOCK
to this SP1 unnecessarly adds this overhead for other places which call SP1 but don't want UPDLOCK
. So one might think to duplicate this SP1 and have new SP1UPDLOCK
which is same as SP1 but with UPDLOCK
. I don't want this duplication.
So is there any way caller can hint that whatever SP1 returns should be take with UPDLOCK.
Any other better way to solve this type of issue.
I'm using SQL server 2008, C#, .NET 4.
Sample Code
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# code
Using(Transaction t = new Transaction())
{
result = SP1(someId);
// some logic here
if(somecond == true)
{
SP2(fooVal, someId);
}
t.Commit();
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
如果 SP2 之后对 SP1 的调用是原子的,则应将它们合并在 T-SQL 中。
或者丢失 c# 事务。您通过往返不必要地延长了事务。
另外,为什么 SP1UPDLOCK 上有 UPDLOCK 而 SP1 上没有?我不明白为什么。如果问题是锁定提示,请不要使用它们。如果某些东西是可序列化的(为什么?),那么再次将其设为单个原子调用
请注意,无论如何默认值都是已提交读
最后,您的意思是“信号量”而不是锁定吗?使用 sp_getapplock 将控制代码流,而无需对数据使用锁定
If the calls to SP1 follows by SP2 are atomic, they should be combined in T-SQL.
Or lose the c# transaction. You are prolonging the transaction unnecessarily with roundtrips.
Also, why have UPDLOCK on SP1UPDLOCK but not for SP1? I can't see why. If the problem is lock hints, don't use them. If something is serializable (why?) then again, make it a single atomic call
Note that the default is READ COMMITTED anyway
Finally, do you mean "semaphore" not lock? Using sp_getapplock will control flow through the code without using locks on the data