如何编写线程安全的SQL Server存储过程

本文关键字:SQL Server 存储过程 安全 何编写 线程 | 更新日期: 2023-09-27 18:09:55

我有一些存储过程,其中正在执行多个查询。为了得到插入的最后一个身份,我使用了IDENT_CURRENT,这引起了问题。

我的问题是,我可以在T-SQL中使用像C#这样的锁语句,这样它就可以是线程安全的吗?

编辑:代码我正在使用

INSERT INTO activities
    (creator
    ,title
    ,description)
VALUES
    (@Creator
    ,@Tile
    ,@Description)
SET @ActivityId = IDENT_CURRENT('dbo.activities');
INSERT INTO [dbo].activity_cfs
    ([activity_id],
    [cf_id],
    [cf_field_name],
    [field_key],
    [value])
SELECT 
    @ActivityId,
    cf_id,
    cf_field_name,
    field_key,
    value
FROM @ActivityCustomFields 

@ActivityCustomFields是我的临时表格。

如何编写线程安全的SQL Server存储过程

很可能应该使用SCOPE_IDENTITY而不是IDENT_CURRENT。它们的区别有很多解释,例如:Scope_Identity((、Identity((、@@Identity和Ident_Current之间的区别是什么?

但是,如果您确实需要保证代码的某些部分不会同时由多个线程运行,则可以使用sp_getapplock


根据您添加到问题中的代码,我现在非常确定您应该简单地使用SCOPE_IDENTITY,如下所示:

INSERT INTO activities
    (creator
    ,title
    ,description)
VALUES
    (@Creator
    ,@Tile
    ,@Description);
SET @ActivityId = SCOPE_IDENTITY();
INSERT INTO [dbo].activity_cfs
    ([activity_id],
    [cf_id],
    [cf_field_name],
    [field_key],
    [value])
SELECT 
    @ActivityId,
    cf_id,
    cf_field_name,
    field_key,
    value
FROM @ActivityCustomFields;

SCOPE_IDENTITY函数返回在同一会话和同一作用域中创建的最后一个标识。IDENT_CURRENT返回为任何会话中的特定表或视图创建的最后一个标识。因此,如果有多个线程同时运行此过程,IDENT_CURRENT将看到在其他线程中生成的标识,这是您不希望的。

SCOPE_IDENTITY将是我理解的方式。请遵循以下链接,在SQL Server中使用SCOPE_IDENTITY时始终是线程安全的:

http://www.vbforums.com/showthread.php?727047-RESOLVED-Is-MSSQL-s-SCOPE_IDENTITY((-线程安全