@@IDENTITY 的缺点 SCOPE_IDENTITY() 取而代之

本文介绍了SQL Server中@@IDENTITY和SCOPE_IDENTITY()的区别,@@IDENTITY可能因忽略操作范围而导致错误,建议使用SCOPE_IDENTITY()来避免此类问题。
      也许大家对SQL Server中的 @@IDENTITY 都不陌生,都知道它是获取数据表中最后一条插入数据的IDENTITY值。
 比如,表 A 中有个 ID 为自增1的字段,假设此时 ID 的值为100,现在如果我往表A插入一条数据,并在插入后
 SELECT @@IDENTITY,则其返回 101,最后一条IDENTITY域(即ID域)的值。
 
 现在问题来了,为什么说要慎用@@IDENTITY呢?原因是 @@IDENTITY 它总是获取最后一条变更数据的自增字段的值,
 而忽略了进行变更操作所在的范围约束。比如,我有表 A 和表 B 两个表,现在我在表 A 上定义了一个Insert触发器,
 当在表 A 中插入一条数据时,自动在表 B 也插入一条数据。此时,大家注意,有两个原子操作:在A中插入一条数据, 接着在B中随后插入一条数据。
 
 现在我们想下,假设上面表 A 和表 B 都有IDENTITY自增域,那么我们在表 A 插入一条数据后,使用了
 SELECT @@IDENTITY 输出时,输出的到底是 A 还是 B 的自增域的值呢?  答案很明显,是谁最后插入就输出谁,
 那么就是 B 了。于是,我本意是想得到 A 的自增域值,结果得到了 B 的自增域值,一只 BUG 随之诞生,搞不好还
 会影响到整个系统数据的混乱。
 
 因此,对于这种情况,建议大家慎用 @@IDENTITY,而尽量采用 SCOPE_IDENTITY() 函数替换之。SCOPE_IDENTITY()
 也是得到最后一条自增域的值,但是它是仅限在一个操作范围之内,而不像 @@IDENTITY 是取全局操作的最后一步操作
 所产生的自增域的值的。
 
在触发器场景下,`@@IDENTITY`返回正确值而`SCOPE_IDENTITY()`返回`NULL`,可能是由以下原因造成的: ### 作用域内无插入到标识列的操作 `SCOPE_IDENTITY()`返回在相同作用域中发生的最后一个插入操作的`IDENTITY`值,如果在当前作用域中调用`SCOPE_IDENTITY()`之前,没有插入语句到标识列,那么该函数将返回`NULL`值。而`@@IDENTITY`不限于特定的作用域,它会返回当前会话中所有表生成的最后一个标识值,只要会话中有插入操作生成了标识值,`@@IDENTITY`就能返回该值[^1]。 以下是一个示例代码,展示这种情况: ```sql -- 创建一个带有自增列的表 CREATE TABLE T1 ( ID INT IDENTITY(1,1) PRIMARY KEY, Name NVARCHAR(50) ); -- 创建一个触发器,在插入数据时不向标识列插入数据 CREATE TRIGGER trg_T1 ON T1 AFTER INSERT AS BEGIN -- 这里没有向标识列插入数据的操作 UPDATE T1 SET Name = Name + '_Updated' WHERE ID IN (SELECT ID FROM inserted); END; -- 执行插入操作 INSERT INTO T1 (Name) VALUES ('Test'); -- 模拟在当前作用域内没有向标识列插入数据就调用 SCOPE_IDENTITY() DECLARE @ScopeIdentityValue INT; SET @ScopeIdentityValue = SCOPE_IDENTITY(); SELECT @ScopeIdentityValue AS ScopeIdentityResult; -- 调用 @@IDENTITY DECLARE @IdentityValue INT; SET @IdentityValue = @@IDENTITY; SELECT @IdentityValue AS IdentityResult; ``` ### 触发器导致的作用域问题 `SCOPE_IDENTITY()`只关注当前作用域内的插入操作。如果触发器执行的插入操作不在当前调用`SCOPE_IDENTITY()`的作用域内,而`@@IDENTITY`由于不受作用域限制,可以捕获到触发器插入操作生成的标识值,此时`SCOPE_IDENTITY()`会返回`NULL`。例如,触发器可能在一个嵌套的存储过程或者子事务中执行插入操作,而调用`SCOPE_IDENTITY()`的代码在外部作用域,这样`SCOPE_IDENTITY()`无法获取到该插入产生的标识值,而`@@IDENTITY`可以[^3][^5]。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值