IDENT_CURRENT常返回“错”的ID,因为它查询sys.identity_columns中该表的last_value,无视事务隔离与会话边界,可能返回其他会话已提交的最新值;安全获取自身插入ID应使用SCOPE_IDENTITY()或OUTPUT子句。

IDENT_CURRENT 能查到指定表的最新自增值,但它不关心当前会话或事务,只返回全局最新值——这意味着并发插入时它可能返回别人刚插的 ID,而不是你自己的。
IDENT_CURRENT 为什么经常返回“错”的 ID?
它查的是系统表 sys.identity_columns 中该表的 last_value,完全无视事务隔离级别和会话边界。比如你刚 INSERT 一条但还没 COMMIT,别人又插了一条并提交了,IDENT_CURRENT('Orders') 就会返回别人的 ID。
- 不是会话安全:跨会话可见
- 不感知事务:未提交的插入不影响它,但别人已提交的会影响它
- 不保证属于你:不能用于“取我刚插的那条 ID”这种场景
真正安全取自己刚插入的 ID,该用什么?
用 SCOPE_IDENTITY() —— 它只返回当前作用域(比如当前存储过程、批处理)内最后生成的 ID,且受事务控制;或者用 OUTPUT 子句直接捕获,最可靠。
-
SCOPE_IDENTITY():推荐日常使用,简单、安全、兼容 SQL Server 2005+ -
@@IDENTITY:慎用,会受触发器里隐式插入影响(比如日志表也带自增,它就返回那个) -
OUTPUT INSERTED.id:最健壮,能一次拿到多列,还支持插入多行时批量获取
示例:
INSERT INTO Orders (amount) OUTPUT INSERTED.id VALUES (99.99);
IDENT_CURRENT 的合理使用场景有哪些?
它只适合做监控或诊断,比如 DBA 想看某张表自增列“走到哪了”,或者排查 ID 跳号是否异常。不能用于业务逻辑中的 ID 关联。
- 检查自增种子是否耗尽:
SELECT IDENT_CURRENT('Users'), IDENT_INCR('Users'), IDENT_SEED('Users') - 对比
MAX(id)和IDENT_CURRENT差值,判断是否有手动SET IDENTITY_INSERT ON导致跳号 - 注意:表名必须是字符串字面量,不能拼接变量,否则报错
Argument data type varchar is invalid for argument 1 of ident_current function.
真正要关联刚插入的数据,别碰 IDENT_CURRENT;它看起来方便,但一并发就出事。用 SCOPE_IDENTITY() 或 OUTPUT 是少踩坑的底线。

















