SR0008:考虑使用 SCOPE_IDENTITY 代替 @@IDENTITY

规则 ID

SR0008

类别

Microsoft.Design

是否重大更改

非重大更改

原因

您的代码中包含 @@IDENTITY 调用。

规则说明

由于 @@IDENTITY 是全局标识值,因此可能已在当前作用域之外更新了该值,并且获得了意外值。 触发器(包括复制使用的嵌套触发器)可以在当前作用域之外更新 @@IDENTITY。

如何解决冲突

若要解决此问题,必须将引用 @@IDENTITY 替换为引用 SCOPE_IDENTITY,后者将返回用户语句作用域中的最新标识值。

何时禁止显示警告

如果在确定没有任何其他处理可能更新过 @@IDENTITY 的值时所使用的语句使用了 @@IDENTITY,则可能要禁止显示此警告。 但是,我们强烈建议您处理警告而非禁止显示它,因为 SCOPE_IDENTITY 提供预期的值,不会有意外更改的风险。

示例

在第一个示例中,在一个向表中插入数据的存储过程中使用了 @@IDENTITY。 然后发布表以进行合并复制,而合并复制向所发布的表添加触发器。 因此,@@IDENTITY 可以从向复制系统表中进行的插入操作而非向用户表中进行的插入操作返回值。

Sales.Customer 表中的最大标识值为 29483。 如果将行插入表,则 @@IDENTITY 和 SCOPE_IDENTITY() 将返回不同的值。 SCOPE_IDENTITY() 从向用户表中进行的插入操作返回值,而 @@IDENTITY 从向复制系统表中进行的插入操作返回值。

第二个示例显示如何才能使用 SCOPE_IDENTITY() 访问所插入的标识值和处理警告。

CREATE PROCEDURE [dbo].[ProcedureWithWarning]
@param1 INT, 
@param2 NCHAR(1),
@Param3 INT OUTPUT
AS
BEGIN
INSERT INTO Sales.Customer ([TerritoryID],[CustomerType]) VALUES (@param1,@param2);

SELECT @Param3 = @@IDENTITY
END

CREATE PROCEDURE [dbo].[ProcedureFixed]
@param1 INT, 
@param2 NCHAR(1),
@param3 INT OUTPUT
AS
BEGIN
INSERT INTO Sales.Customer ([TerritoryID],[CustomerType]) VALUES (@param1,@param2);

SELECT @Param3 = SCOPE_IDENTITY()
END

请参见

概念

分析数据库代码以提高代码质量