scope_identity() 返回当前会话、当前作用域中最后插入的自增列值;它作用域隔离、会话安全,不受触发器干扰,且必须与 insert 在同一语句批中调用,否则可能失效。

SCOPE_IDENTITY() 返回什么值?
它返回当前会话、当前作用域中最后插入的自增列值。关键在“当前作用域”——比如存储过程中执行的 INSERT,不会被触发器里另一个 INSERT 干扰,这点比 @@IDENTITY 更安全。
为什么不能用 @@IDENTITY 或 IDENT_CURRENT?
@@IDENTITY 会跨作用域捕获触发器内生成的 ID,容易出错;IDENT_CURRENT('table_name') 是全局的,不绑定会话也不绑定作用域,多用户并发时可能拿到别人刚插的 ID。
- 触发器存在时,
@@IDENTITY几乎必然错 -
IDENT_CURRENT需手动传表名,且结果不可预测 -
SCOPE_IDENTITY()是三者中唯一既会话安全又作用域隔离的
怎么在 INSERT 后立刻拿到 ID?
必须在同一语句批(batch)中调用,不能分两个独立查询执行。常见错误是:先执行 INSERT,再另起一个 SELECT SCOPE_IDENTITY() —— 如果中间有其他语句(哪怕只是 PRINT 或变量赋值),就可能破坏作用域连续性。
推荐写法:
INSERT INTO users (name, email) VALUES ('Alice', 'a@example.com');
SELECT SCOPE_IDENTITY() AS new_id;
或者更稳妥地封装进变量:
DECLARE @new_id INT;
INSERT INTO users (name, email) VALUES ('Bob', 'b@example.com');
SET @new_id = SCOPE_IDENTITY();
使用时要注意哪些边界情况?
如果 INSERT 没有实际插入行(比如被 WHERE 过滤掉、或遇到约束失败回滚),SCOPE_IDENTITY() 仍会返回上一次成功插入的 ID,而不是 NULL 或报错。这容易埋下逻辑漏洞。
- 务必检查
@@ROWCOUNT == 1再读取SCOPE_IDENTITY() - 事务中若发生回滚,
SCOPE_IDENTITY()不会回退,但该 ID 已无效,不应再使用 - 表没设自增主键时,函数返回
NULL,需做空值判断
真正可靠的做法是把插入和取 ID 放在同一个原子操作里,别指望后续补查。










