sql - 池化 SQL 表的 2 个应用程序之间的同步
问题描述
我有 2 个 VB.NET 应用程序实例,每个实例都在自己的专用服务器上运行。所述应用程序在 IDLE 上运行 5s 睡眠的 While true 循环(IDLE 是当表没有任何 ProcessQuery 要处理时)。在每次迭代中,应用程序都会询问 SQL 数据库中的一个表,以了解它是否可以处理任何内容。
问题是我有时会遇到两个实例都“采用”相同 ProcessQuery 的问题。
我正在使用 EntityFramework6。我已经研究过 EntityState,但我认为它并没有完全达到我想要完成的目的。
我想知道拥有完美并行实例的解决方案是什么。在某些时候,我在 12 台机器上运行 12 个实例并非不可能。
谢谢!
Dim conn As New Info_IndusEntities()
Dim DemandeWilma As WilmaDemandes = conn.WilmaDemandes.Where(Function(x) x.Site = 'LONDON' AndAlso x.Statut = 'toProcess').OrderBy(Function(x) x.RequestDate).FirstOrDefault
If Not IsNothing(DemandeWilma) Then
DemandeWilma.Statut = Statuts.EnTraitement.ToString
DemandeWilma.ServerName = Environment.MachineName
DemandeWilma.ProcessDate = DateTime.Now
conn.SaveChanges()
Return DemandeWilma
end if
更新(21/06/19)
我发现了一篇我觉得很有趣的文章。
更新(21/06/19)
然后我刷新了我的模型并更改了我的 ORM 中 RowVersion 列的Concurrency Check属性:
当我测试更新时,这里是 EF6 的日志:
UPDATE [dbo].[WilmaDemandes] SET [Statut] = @0, [ServerName] = @1, [DateDebut] = @2 WHERE (([ID] = @3) AND ([RowVersion] = @4)) SELECT [RowVersion] 来自 [dbo].[WilmaDemandes] 其中@@ROWCOUNT > 0 AND [ID] = @3
-- @0: 'EnTraitement'(类型 = 字符串,大小 = 20)
-- @1: 'TRB5995' (类型 = 字符串,大小 = 20)
-- @2: '2019-06-25 7:31:01 AM' (类型 = DateTime2)
-- @3: '124373' (类型 = Int32)
-- @4: 'System.Byte[]' (类型 = 二进制,大小 = 8)
-- 执行时间:2019-06-25 7:31:24 AM -04:00
-- 在 95 毫秒内完成,结果为:SqlDataReader
2019-06-25 7:31:24 AM -04:00 关闭连接
抛出异常:EntityFramework.dll 中的“System.Data.Entity.Infrastructure.DbUpdateConcurrencyException”
更新(25/06/19)
如本文所述,问题始于您使用 DB-First 而不是 Code-First。更新模型后,您的属性将被静默覆盖。当时有些人编写了一个控制台应用程序解决方法,他们在预构建时运行。我不确定我是否准备好将此解决方案作为最终解决方案。
关于如何测试乐观并发以及解决此类异常的方法的有趣教程。
解决方案
- 将“所有者”列添加到您的队列表
- 您的应用程序更新了一条记录(TOP 1)并将所有者值设置为其标识符(WHERE Owner IS NULL)
- 现在您的应用程序返回并读取它们拥有的行并处理它们
这是一个简单的模式,效果很好。如果任何进程碰巧“同时”取得所有权,那么实际上只有一个进程会获得保留。
我不太擅长 LINQ,所以这里有一个蛮力方法,为了清楚起见多行:
// First try reserving a row
conn.Database.ExecuteSqlCommand(
"WITH UpdateTop1 AS
(SELECT TOP 1 * FROM WilmaDemandes
WHERE Owner IS NULL
AND Site = 'LONDON'
ORDER BY RequestDate)
UPDATE UpdateTop1 SET Owner='ThisApplication'"
);
// See if we got one
Dim DemandeWilma As WilmaDemandes =
conn.WilmaDemandes.
Where(x => x.Owner=='ThisApplication').FirstOrDefault
// If we got a row, process it. Otherwise Idle and repeat
您也没有理由必须保留一排。您可以保留所有空闲行并按照自己的方式处理它们。同时,其他进程将拾取任何随后到达的行
就我个人而言,我会重构您的状态列并将其设置为 NULL 以用于准备处理的新记录,否则它是保留它的工作人员 ID。
它还有助于添加时间戳列等内容以记录保留行的时间等。
推荐阅读
- terraform - 如何从 AWS 控制台派生策略转变为有效的 terraform 脚本策略?
- c++ - 如果跨 2 个线程使用,是否值得将 size_t 声明为 std::atomic?
- authentication - 403 - 禁止:访问被拒绝。登录 ASP.Net Core 2.2 后
- android - 为什么我无法在 Kotlin 中读取 ArrayList 的内容
- java - 如何修复 Intellij 中的“运行”按钮?
- java - 当我在 pom.xml 中添加我的依赖项时,Tomcat 不起作用
- android - java.lang.NullPointerException:尝试调用虚拟方法android studio
- database - 如何使用elasticsearch计算增长率
- python - 查找文件夹图片的位置
- tensorflow - 如何在我的张量流模型中将所有相关的 uint8 实例更改为 int8