我尝试过使用事务并将事务隔离级别设置为可序列化,但仍然遇到同样的问题。
这是重现我的问题的方法:
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
我希望多次运行该程序而不会出现错误。
看起来
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;
不过,我坚持认为,如果您不断删除并重新创建同一个表,那么您可能做错了什么。