sql-server - 如何使用实体框架更新一个事务中的选定记录?
问题描述
我正在使用 SQL Server。我的情况是这样的:
- 我有一张桌子
Messages
。该表有一列MessageStatusId
- 我有几个服务可以访问这个数据库
- 每个服务定期选择带有状态的
New
消息并以某种方式处理这些消息 - 服务选择消息,例如:
await DbContext.Set<Message>() .Where(m => m.MessageStatusId == MessageStatusEnum.New) .ToListAsync();
- 处理后,服务更新消息状态
我不希望服务选择同一组记录。所以我需要将消息状态更新为InProcess
. 如何使用实体框架在一次事务中实现这一点?
解决方案
您可以实施悲观锁定以确保一次只有一个工作人员访问表,但是保持表访问尽可能短以避免客户端之间的死锁非常重要。我建议每个请求获取有限数量的行:
var options = new TransactionOptions
{
IsolationLevel = System.Transactions.IsolationLevel.Serializable,
Timeout = new TimeSpan(0, 0, 0, 10)
};
var messageIds = new List<int>();
using(var scope = new TransactionScope(TransactionScopeOption.RequiresNew, options))
{
using (var context = new MessageDbContext())
{
var messages = context.Messages
.Where(x => x.MessageStatusId == MessageStatusEnum.New)
.OrderBy(x => x.MessageDate)
.Take(100)
.ToList();
foreach(var message in messages)
message.MessageStatusId = MessageStatusEnum.InProgress;
context.SaveChanges();
messageIds = messages.Select(x => x.MessageId).ToList();
}
scope.Commit();
}
我的建议是:
- 将此 Message 实体分离到一个有界 DbContext 中,该 DbContext 仅服务于消息检查/状态更新,没有别的。此消息实体可能只是用于此操作的 MessageId 和 MessageStatusId 以及其他用于检查消息状态/w 悲观锁定的实体。
- 使用同步调用,比异步更快。
- 获取行,将它们标记为进行中并获取它们的 ID,然后提交状态更改。您可以在之后使用乐观锁定阅读它们,以便在闲暇时处理并避免死锁。
- 如果碰巧有大量积压,请限制查询的行数以避免意外。(10、100,任何合理的)
推荐阅读
- python - 搜索字符串并在包含字符串的行之后打印 3 行
- javascript - 为以特定字母开头的单词添加样式并使其在 javascript 中可点击
- html - div 中的背景图像没有占据整个视图
- mysql - MySQL:将单行结果放在单独的列中
- delphi - 在受 DPI 缩放影响的 Delphi VCL 应用程序中使用 Direct2D
- javascript - 价值 || '-', 也显示 0
- c# - MVC 路由 URL 到区域控制器
- c# - 如何在 C# 中获取设备的时钟系统?(12 小时或 24 小时)
- r - 如何附加包含非导出功能的包?
- javascript - Clarifai - 人脸检测 - 方法不允许