Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/sql-server/26.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Sql 没有行,但(XLOCK,ROWLOCK)已将其锁定?_Sql_Sql Server_Sql Server 2005_Sql Server 2008 - Fatal编程技术网

Sql 没有行,但(XLOCK,ROWLOCK)已将其锁定?

Sql 没有行,但(XLOCK,ROWLOCK)已将其锁定?,sql,sql-server,sql-server-2005,sql-server-2008,Sql,Sql Server,Sql Server 2005,Sql Server 2008,考虑一下这个简单的表: 表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

考虑一下这个简单的表:

表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个SSM运行这个脚本,并逐步运行这2个脚本(在调试模式下)。有趣的是,当reach
IF EXIST
语句锁定表时,我的表没有行,只有一个脚本

我的问题是
(XLOCK,ROWLOCK)
是否因为没有行而锁定整个表?还是它锁定幻影行:)

编辑1)

这是我的设想:

我有一个表,其中有6个字段

这是唯一性规则:

1) 城市代码+F1代码是唯一的

2) 城市代码+F2代码是唯一的

3) 城市代码+F3代码+F4代码为uinque

问题是用户可能希望填写
city\u code
F1\u code
,并且当用户希望将其插入其他文件时,必须具有
空字符串
0
(对于数字字段)值

如果用户希望填写城市代码+F3代码+F4代码,则F1代码和F2代码必须具有空字符串


如何更好地检查这个问题?我不能为每个规则创建任何唯一的索引

XLOCK是独占锁:因此在遍历行的地方,行被锁定

SET TRANSACTION ISOLATION LEVEL SERIALIZABLE与行的重复或锁定无关,它只是消除了重复的可能性。从锁定的角度来看,它采用范围锁定(例如a和B之间的所有行)

因此,使用XLOCK和SERIALIZABLE可以锁定表。你想要的是非独占的UPDLOCK

使用UPDLOCK时,此模式不安全。在高负载下,您仍然会得到重复的错误,因为2个并发的存在将找不到一行,两个都尝试插入,一个会得到重复的错误

因此,请尝试插入并捕获错误:

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
我提到过这个

编辑:强制SQL Server 2008使用各种Unique

使用筛选索引

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 = '';

您可以对早期版本上的索引视图执行相同的操作

要回答您的问题,可序列化隔离级别将执行范围锁定,其中包括范围内不存在的行

钥匙范围锁定可确保执行以下操作: 可序列化:

范围扫描查询

不存在行的单例获取

删除操作

插入操作


+这本书读得不错,但现在我想知道。在这种情况下,隔离级别不处理重复项吗?谢谢,但问题是我的列不是主键,它们上没有索引。如果我运行INSERT,任何一行都可以INSERT。为什么你说我可以得到两行?我说如果存在,则得到的每个事务都会锁定table@Lieven:不,没有。隔离级别与重复检查无关:SERIALIZABLE只是删除“幻影读取”@Nima:在这种情况下,您就不会关心重复,因为您没有唯一的约束。那么为什么要先测试呢?你的代码有什么意义。。。?假设您有一百万行,那么整个表将被锁定,因为没有索引,您要求锁定表(使用XLOCK和SERIALIZABLE)。太好了。非常感谢。你是一名出色的sql server管理员。非常好。你能再解释一下对不存在的行的
单例提取吗?
。这对我来说听起来很疯狂。thanksA serializable scan获得了一个密钥范围锁,可以防止在范围内的任何位置插入任何新行(以及更新或删除范围内的任何现有行)。这包括选择一个不存在的行(尚未?)singleton fetch就是简单地选择一条记录,如果该行不存在,它在事务期间仍会锁定该键值。这是针对SQL Server 2005还是SQL Server 2008的:这对解决方案很重要。。。