悲观地锁定进程之间的代码
Pessimistically locking code between processes
我们有以下进程可以修改同一个数据集:
- 网站(Asp.NET Web API 修改了一些 parent/child 数据集)
- Azure Web 作业(修改相同 parent/child 数据集的 C# 代码)
当 Parent/Child 数据集被两个进程同时修改时,推荐的方法是什么来确保我们保持数据完整性(C# Lock 语句将不起作用,因为它的代码 运行 在不同的进程)。
目前他们正在使用 Entity Framework,该过程会将数据集加载到内存中,处理数据,然后保存。问题是数据最初被进程B读取后,可能会被另一个进程A更改。
数据在 SQL Azure 数据库中。
我能否在父 table 记录 (Id = XXXX) 上创建一个阻塞事务,这样其他进程只需等待锁被释放。如何最好地做到这一点?
否则,我脑海中浮现出的一些其他想法可能是在父记录上设置一个 "Locked" 字段,或者检查每个子 table 的父 UNION 的 MAX RowVersion (对于父 ID)并在每次更改之前和之后检查此 RowVersion?
sp_getapplock 存储过程似乎正是您所需要的。
当您想要同步需要独占访问数据库的一部分的进程时,它非常有用。
这应该像下面这样。其中 ctx
是 DbContext
,并且您要同步的每个进程都使用相同的共享逻辑名称字符串 "MYLOCKNAME",或您想要的任何名称。
using (var tran = ctx.Database.BeginTransaction())
{
try
{
const string lockName = "MYLOCKNAME";
var resourceParam = new SqlParameter("Resource", SqlDbType.NVarChar, 255) { Value = lockName };
var lockModeParam = new SqlParameter("LockMode", SqlDbType.NVarChar, 32) { Value = "Transaction" };
ctx.Database.ExecuteSqlCommand("EXEC sp_getapplock @Resource, @LockMode", resourceParam, lockModeParam);
// Do stuff with ctx
// ...
tran.Commit();
}
catch
{
tran.Rollback();
}
}
我们有以下进程可以修改同一个数据集:
- 网站(Asp.NET Web API 修改了一些 parent/child 数据集)
- Azure Web 作业(修改相同 parent/child 数据集的 C# 代码)
当 Parent/Child 数据集被两个进程同时修改时,推荐的方法是什么来确保我们保持数据完整性(C# Lock 语句将不起作用,因为它的代码 运行 在不同的进程)。
目前他们正在使用 Entity Framework,该过程会将数据集加载到内存中,处理数据,然后保存。问题是数据最初被进程B读取后,可能会被另一个进程A更改。
数据在 SQL Azure 数据库中。
我能否在父 table 记录 (Id = XXXX) 上创建一个阻塞事务,这样其他进程只需等待锁被释放。如何最好地做到这一点?
否则,我脑海中浮现出的一些其他想法可能是在父记录上设置一个 "Locked" 字段,或者检查每个子 table 的父 UNION 的 MAX RowVersion (对于父 ID)并在每次更改之前和之后检查此 RowVersion?
sp_getapplock 存储过程似乎正是您所需要的。
当您想要同步需要独占访问数据库的一部分的进程时,它非常有用。
这应该像下面这样。其中 ctx
是 DbContext
,并且您要同步的每个进程都使用相同的共享逻辑名称字符串 "MYLOCKNAME",或您想要的任何名称。
using (var tran = ctx.Database.BeginTransaction())
{
try
{
const string lockName = "MYLOCKNAME";
var resourceParam = new SqlParameter("Resource", SqlDbType.NVarChar, 255) { Value = lockName };
var lockModeParam = new SqlParameter("LockMode", SqlDbType.NVarChar, 32) { Value = "Transaction" };
ctx.Database.ExecuteSqlCommand("EXEC sp_getapplock @Resource, @LockMode", resourceParam, lockModeParam);
// Do stuff with ctx
// ...
tran.Commit();
}
catch
{
tran.Rollback();
}
}