考虑这个简单的表格:
表create语句是:
CREATE TABLE [dbo].[Test_Serializable](
[Id] [int] NOT NULL,
[Name] [nvarchar](50) NOT NULL
)
所以没有任何主键或索引。
认为它是emopty并且没有任何行。我想要插入此行(1,'nima')
但我想检查是否有一行Id=1
或者没有。如果是,请致电RAISERROR
如果没有插入行。我写这个脚本:
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE
BEGIN TRY
BEGIN TRAN ins
IF EXISTS(SELECT * FROM Test_Serializable ts WITH(xlock,ROWLOCK) WHERE ts.Id=1)
RAISERROR(N'Row Exists',16,1);
INSERT INTO Test_Serializable
(
Id,
[Name]
)
VALUES
(
1,
'nima'
)
COMMIT TRAN ins
END TRY
BEGIN CATCH
DECLARE @a NVARCHAR(1000);
SET @a=ERROR_MESSAGE();
ROLLBACK TRAN ins
RAISERROR(@a,16,1);
END CATCH
这个脚本运行正常,但有一点很有趣。
我从2个SSMS运行这个脚本并逐步运行这2个脚本(在调试模式下)。但是,有趣的是,当到达IF EXIST
语句锁定表时,我的表没有行但只有一个脚本。
我的问题是(XLOCK,ROWLOCK)
是否锁定整个表,因为没有行?或者锁定幻像行:) !! ???
编辑1)
这是我的情景:
我有一个表格,例如6个字段
这是唯一性规则:
1)City_Code + F1_Code是唯一的
2)City_Code + F2_Code是唯一的
3)City_Code + F3_Code + F4_Code是uinque
问题是用户可能想要填充city_code
和F1_Code
,当它想要将其插入其他文件时,我们必须Empty String
或0
(对于数字字段)值。
如果用户想要填充City_Code + F3_Code + F4_Code,则F1_Code和F2_Code必须具有Empty String
值
如何更好地检查?我无法为每个规则创建任何唯一索引
答案 0 :(得分:5)
要回答您的问题,SERIALIZABLE隔离级别会执行范围锁定,其中包括范围内不存在的行。
http://msdn.microsoft.com/en-us/library/ms191272.aspx
键范围锁定可确保执行以下操作 序列化:
范围扫描查询
单点提取不存在的行
删除操作
插入操作
答案 1 :(得分:4)
XLOCK是独占锁:因此当WHERE遍历行时,行被锁定。
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE不是关于行的重复或锁定,它只是删除"Phantom reads"的机会。从锁定的角度来看,它需要范围锁(例如A和B之间的所有行)
因此,使用XLOCK和SERIALIZABLE,您可以锁定表格。你想要的UPDLOCK不是唯一的。
使用UPDLOCK,此模式不安全。在高负载下,您仍然会遇到重复错误,因为2个并发EXISTS将找不到行,两者都尝试INSERT,一个会出现重复错误。
因此,只需尝试INSERT并捕获错误:
BEGIN TRAN ins
INSERT INTO Test_Serializable
(
Id,
[Name]
)
VALUES
(
1,
'nima'
)
COMMIT TRAN ins
END TRY
BEGIN CATCH
DECLARE @a NVARCHAR(1000);
IF ERROR_NUMBER() = 2627
RAISERROR(N'Row Exists',16,1);
ELSE
BEGIN
SET @a=ERROR_MESSAGE();
RAISERROR(@a,16,1);
END
ROLLBACK TRAN ins
END CATCH
我已经提到了before
编辑:强制SQL Server 2008的各种唯一身份用户
使用过滤的索引
CREATE UNIQUE NONCLUSTERED INDEX IX_UniqueF1 ON (City_Code, F1_Code)
WHERE F2_Code = '' AND F3_Code = '' AND AND F4_Code = 0;
CREATE UNIQUE NONCLUSTERED INDEX IX_UniqueF1 ON (City_Code, F2_Code)
WHERE F1_Code = '' AND F3_Code = '' AND AND F4_Code = 0;
CREATE UNIQUE NONCLUSTERED INDEX IX_UniqueF3F4 ON (City_Code, F3_Code, F4_Code)
WHERE F1_Code = '' AND F2_Code = '';
您可以对早期版本的索引视图执行相同的操作