SQL Server 2019事务内用SELECT TOP 1倒序查刚插入行是否正确
事务内插入后倒序取TOP 1获取刚插入行的正确性说明
结论
这种写法不能保证始终正确,仅在完全没有并发写入的场景下能拿到预期结果,生产环境使用存在极高的取错数据风险。
错误原因
- 自增ID的分配逻辑独立于事务:数据库的自增标识(identity)分配是全局串行的,不受事务隔离性约束,只要有插入请求就会按顺序分配ID,就算申请ID的事务最终回滚,已分配的ID也不会被回收。如果有其他并发事务在你当前事务的
INSERT和SELECT语句之间完成了插入操作,会生成比你本次插入更大的ID值,此时倒序取TOP 1拿到的就是其他事务插入的行。 - 常规事务隔离级别无法避免该问题:哪怕使用大多数数据库默认的可重复读隔离级别,也只能保证你读取到的已存在数据不会被其他事务修改,无法阻挡其他事务插入新的更大ID的行,这类幻读场景在常规隔离级别下是允许的,只有调整为性能极差的串行化隔离级别才能规避,完全不具备实用性。
正确替代方案
根据你提供的语法判断你使用的是SQL Server,推荐两种100%可靠的写法:
- 单条插入场景可使用
SCOPE_IDENTITY()函数,获取当前会话、当前作用域最后生成的自增ID:
BEGIN TRANSACTION INSERT INTO [MyTable] ([description], [name]) VALUES ('animal', 'cat') SELECT [id], [description], [name] FROM [MyTable] WHERE [id] = SCOPE_IDENTITY() COMMIT TRANSACTION
- 兼容单条/批量插入的
OUTPUT子句写法,直接返回当前插入操作的行数据,无需二次查询:
BEGIN TRANSACTION INSERT INTO [MyTable] ([description], [name]) OUTPUT inserted.[id], inserted.[description], inserted.[name] VALUES ('animal', 'cat') COMMIT TRANSACTION
如果是MySQL场景,对应可以使用2348496函数实现相同效果,逻辑完全一致。
内容的提问来源于stack exchange,提问作者Mike97
相关产品推荐
相关产品推荐

