You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

.NET IsolationLevel.ReadCommitted事务生成唯一托运编号偶发重复问题

重复编号问题根因

该问题和事务隔离级别有一定关联,但核心原因是代码的「读-改-写」操作非原子:

  • 并发请求可以在同一时间读取到相同的NextConsignmentNumber值,后续各自执行+1更新操作,最终两个请求返回相同编号,数据库的数值仅累加1次,就会出现重复。
  • 你提到的Serializable隔离级别下依然出现问题符合官方文档描述:主流数据库的Serializable隔离级别默认对普通SELECT语句使用快照读,不会加行锁,只有写操作才会触发锁逻辑,所以还是会出现两个事务读到同个值的情况。
  • 多租户架构下只有同租户的并发请求会触发该问题,所以只会在极少数高并发场景下复现。

修复方案

方案1:原子更新(最优选择)

直接用数据库层面的原子更新语句,避免拆分读和写两个操作,SQL逻辑示例如下:

UPDATE TenantSettings 
SET SettingValue = CAST(SettingValue AS INT) + 1
WHERE TenantId = @TenantId AND SettingName = @SettingName
OUTPUT DELETED.SettingValue;

你可以基于ABP框架的SettingManager扩展对应原子更新方法,全程仅一次数据库写操作,完全规避并发冲突,性能远高于其他方案,也不需要调整事务隔离级别。

方案2:读操作加排他锁

如果不想修改Setting的底层操作逻辑,可以在读取NextConsignmentNumber时对行加排他锁,让并发的读操作阻塞,保证同一时间只有一个事务能拿到当前值。以SQL Server为例,读取语句增加WITH (UPDLOCK, HOLDLOCK)提示即可。

方案3:乐观锁控制

在租户配置表增加RowVersion版本号字段,更新时校验版本号是否和读取时一致,不一致就重试直到更新成功,该方案适合并发量不高的场景,不需要加锁,但要额外处理重试逻辑。

验证建议

修复完成后可模拟同租户100并发连续创建运单的场景,验证是否还会生成重复编号,确保修复生效。

内容的提问来源于stack exchange,提问作者Rick Wheeler

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.07 01:12:02