使用Entity Framework 4.5处理并发消费时重复记录问题求助
解决EF4.5并发插入重复记录问题
你的问题根源在于查询记录是否存在与插入新记录是两个非原子操作,高并发下多个请求会同时通过“不存在”的判断,最终重复插入相同reference值的记录。以下是几个可行的解决办法:
1. 数据库层面加唯一约束(最可靠的方案)
这是从根源杜绝重复的手段,不管代码逻辑如何,数据库直接拦截重复值插入:
- 给
sale表的reference字段添加唯一约束(或唯一索引)。当多个请求同时执行插入时,数据库会抛出唯一性冲突异常,确保数据不会重复。 - 代码中需要捕获该异常,返回对应的处理结果。修正后的参考代码:
[HttpPost] public sale process(JObject json) { using (Entity con = new Entity()) // 使用using确保上下文及时释放 { string id = generateId(); string idSias = (string)json["idSias"]; var sale = con.sale.Where(sa => sa.reference == idSias).FirstOrDefault<sale>(); if (sale != null) { return null; } var newSale = new sale { id = id, reference = idSias }; con.sale.Add(newSale); try { con.SaveChanges(); return newSale; // 原代码返回查询的sale(为null),这里应返回新建的记录 } catch (UpdateException ex) { // 针对SQL Server的唯一性冲突异常(错误码2627),其他数据库需调整判断逻辑 if (ex.InnerException is SqlException sqlEx && sqlEx.Number == 2627) { return null; // 或返回重复提示信息 } throw; // 其他异常正常抛出 } } }
2. 代码层面使用悲观锁(辅助方案)
通过在查询阶段锁定资源,阻止其他请求同时执行插入操作。EF4.5支持通过With(LockMode.PessimisticWrite)添加悲观写锁(需数据库支持,如SQL Server):
var sale = con.sale .Where(sa => sa.reference == idSias) .With(LockMode.PessimisticWrite) // 锁定查询相关的行范围 .FirstOrDefault<sale>();
注意:这种方式会降低并发性能,且如果查询的记录不存在,锁的范围可能无法完全阻止重复插入,因此仅作为辅助手段,优先推荐数据库唯一约束。
3. 修正代码中的错误
原代码存在两处逻辑错误,需先修正:
- 变量名错误:
if (ventaSias != null)应改为if (sale != null),否则判断逻辑完全失效; - 返回值错误:原代码返回的是查询得到的
sale(不存在时为null),应返回新建的newSale才符合业务逻辑。
内容的提问来源于stack exchange,提问作者Osmar Barrientos Chuveyzer
相关产品推荐
相关产品推荐

