如何防止 SQL Server 上的竞争条件?

问题描述 投票:0回答:1

我尝试过使用事务并将事务隔离级别设置为可序列化,但仍然遇到同样的问题。

这是重现我的问题的方法:

CREATE PROCEDURE dbo.TestRaceCondition
AS
DROP TABLE IF EXISTS dbo.TABLE_A;
WAITFOR DELAY '00:00:01';
SELECT 1 ID INTO dbo.TABLE_A;
GO

在 3 个不同的会话中多次复制并粘贴以下代码(我复制了 20 次)

EXEC dbo.TestRaceCondition;
GO

然后尝试同时执行 3 个会话。

这是我在至少一个会话中遇到的错误:

消息 2714,级别 16,状态 6,过程 dbo.TestRaceCondition,第 46 行 数据库中已有一个名为“TABLE_A”的对象。

希望有人能帮助我,先谢谢你了!

我尝试过使用交易

CREATE PROCEDURE dbo.TestRaceCondition
AS
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE
BEGIN TRAN
DROP TABLE IF EXISTS dbo.TABLE_A;
WAITFOR DELAY '00:00:01';
SELECT 1 ID INTO dbo.TABLE_A;
COMMIT TRAN
GO

我希望多次运行该程序而不会出现错误。

sql-server t-sql transactions race-condition
1个回答
0
投票

看起来

DROP TABLE IF EXISTS
只是暂时应用了
Sch-S
锁,如果需要删除该表才升级为
Sch-M
锁。

虽然有很多方法可以强制

Sch-M
锁,但更惯用的方法可能是使用
sp_getapplock
,它可以创建任意应用程序定义的锁。

CREATE PROCEDURE dbo.TestRaceCondition
AS

SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;
SET NOCOUNT, XACT_ABORT ON;
BEGIN TRAN;

EXEC sp_getapplock @Resource = N'TestRaceCondition', @LockMode = 'Update';

DROP TABLE IF EXISTS dbo.TABLE_A;

WAITFOR DELAY '00:00:01';

SELECT 1 ID INTO dbo.TABLE_A;

EXEC sp_releaseapplock @Resource = N'TestRaceCondition';

COMMIT TRAN;

不过,我坚持认为,如果您不断删除并重新创建同一个表,那么您可能做错了什么。

© www.soinside.com 2019 - 2024. All rights reserved.