我有以下情况:
目前,在创建新秩序时,这一要求的实现如下:
var newOrder = /* logic for creating the new order */;
var orders = _ordersRepository.GetAllBy(userId, date); // get the orders from the db
var totalAmount = orders.Sum(o => o.Amount);
if(totalAmount < MaximumAmount) {
newOrder.IsApproved = true;
}
else {
newOrder.IsApproved = false;
}
_ordersRepository.Add(newOrder);
_ordersRepository.SaveChanges(); // insert into the db这种方法的问题在于它不能在以下场景中正确地处理并发插入:
500美元
请求是并发处理的,由于时间很短,在将新订单保存到数据库之前执行当前实现的检查,因此允许创建所有这些订单。最后,用户结束超过最大限制。
我如何解决这个问题,理想情况下不需要多次调用SaveChanges?我使用的是实体框架核心5和Server。
发布于 2021-05-10 11:19:14
感谢您的意见和建议!
我尝试使用IsolationLevel设置为Serializable的事务,但后来我意识到这会锁定太多的表(问题中的示例是一个虚拟的,实际的实现要复杂得多)。
我同意有时在数据库中使用这种逻辑可能更容易,但是为此添加一个存储过程会破坏当前的一致性,并且很可能会为其他存储过程打开大门。我并不是说存储过程是不好的,只是在我目前的情况下,即使没有存储过程,实现存储过程也会更加困难/更复杂,但我认为,出于一致性的原因,这是值得的。
我最后的解决方案
我已经将流程分成两个步骤,如下所示:
// step 1
var newOrder = /* logic for creating the new order */;
_ordersRepository.Add(newOrder);
_ordersRepository.SaveChanges(); // insert into the db
// step 2
var orders = _ordersRepository.GetAllBy(userId, date); // get the orders from the db
var totalAmount = orders.Sum(o => o.Amount);
if(totalAmount < MaximumAmount) {
newOrder.IsApproved = true;
}
_ordersRepository.Update(newOrder);
_ordersRepository.SaveChanges(); // update the new orderfalse.
IsApproved标志留给默认的
IsApproved标志将传递给true.。
我知道这不是一个真正的解决方案,而是一个解决办法。锁定一个表可能会产生太大的性能影响,特别是如果给定的表被多个应用程序功能所使用。使用此解决方案,即使步骤2中有问题,订单也将留给IsApproved=false,因此不会产生任何影响,用户可以稍后再试,或者支持人员可以处理它。
https://stackoverflow.com/questions/67456042
复制相似问题