使用IDENT_CURRENT()在插入时获取ID是否存在并发问题?
问题解答
你的担忧完全合理,多用户并发插入时确实会出现ID赋值错误的情况
IDENT_CURRENT('ExampleTable') 返回的是指定表全局范围内最后生成的标识值,和当前会话、作用域无关。举个实际场景:
- 用户A执行INSERT前,获取到的
IDENT_CURRENT是100; - 此时用户B先完成插入操作,表的标识值被更新为101;
- 用户A的INSERT语句执行时,会用101来拼接
ExampleCompositeNumber,但实际插入行的ExampleID是102,直接导致字段值和实际ID不匹配。
而你提到的SCOPE_IDENTITY()确实无法解决这个问题——它返回的是当前作用域内上一次插入的标识值,在这条INSERT语句执行时,当前行的标识值还未生成,所以要么拿到的是之前插入的旧ID,要么就是NULL,完全不符合需求。
正确的实现方案
方案1:使用OUTPUT子句获取当前插入ID
先插入占位值,再通过OUTPUT拿到的真实ID更新字段:
DECLARE @InsertedIDs TABLE (ExampleID int); -- 先插入空占位 INSERT INTO ExampleTable (ExampleCompositeNumber) OUTPUT inserted.ExampleID INTO @InsertedIDs VALUES (NULL); -- 用真实ID更新复合字段 UPDATE ExampleTable SET ExampleCompositeNumber = CAST(t.ExampleID AS nvarchar(18)) + '-123345' FROM ExampleTable t JOIN @InsertedIDs i ON t.ExampleID = i.ExampleID;
方案2:使用计算列(推荐)
如果ExampleCompositeNumber的规则是固定基于ExampleID生成,直接把它设为计算列,无需手动插入,永远不会出错:
-- 先删除原有字段 ALTER TABLE ExampleTable DROP COLUMN ExampleCompositeNumber; -- 添加计算列,自动生成符合格式的值 ALTER TABLE ExampleTable ADD ExampleCompositeNumber AS CAST(ExampleID AS nvarchar(18)) + '-' + RIGHT('000000' + CAST(ABS(CHECKSUM(NEWID())) % 1000000 AS nvarchar(6)),6) PERSISTED;
注:这里用NEWID()生成000000-999999的随机数,PERSISTED关键字会把计算结果存储到磁盘,支持创建索引提升查询性能。
方案3:使用AFTER INSERT触发器
创建触发器,插入完成后自动更新字段:
CREATE TRIGGER trg_SetExampleCompositeNumber ON ExampleTable AFTER INSERT AS BEGIN UPDATE ExampleTable SET ExampleCompositeNumber = CAST(i.ExampleID AS nvarchar(18)) + '-123345' FROM ExampleTable t JOIN inserted i ON t.ExampleID = i.ExampleID; END;
之后插入数据时无需指定ExampleCompositeNumber,触发器会自动生成正确的值。
总结
- 用
IDENT_CURRENT的方式在多用户并发场景下必然会出现ID不匹配的问题,你的担忧完全正确; SCOPE_IDENTITY()无法获取当前插入行的ID,不适用这个场景;- 最稳妥的方式是使用计算列(规则固定时),或者用OUTPUT子句、触发器来保证字段值和真实ID的一致性。
内容的提问来源于stack exchange,提问作者Elias
相关产品推荐
相关产品推荐

