我正在尝试使用实体框架编写一个
SELECT... FOR UPDATE
查询(对于Postgresql
数据库)。问题是,使用任何 IsolationLevel
,第二个请求只会在更新数据后阻塞(图中的步骤 2),而不是从第一个请求(获取图中的响应步骤)开始阻塞。 Chaos
不支持级别(不知道为什么)。
即使从选择中我也需要锁定资源,否则两个请求将占用相同的资源!
我找不到使用 EF 的解决方案,但这可以使用 SQL 函数(+迁移),这不是首选!
谢谢
// Serializable Summary
// A range lock is placed on the System.Data.DataSet, preventing other users from
// updating or inserting rows into the dataset until the transaction is complete.
await using var transaction = await _dbContext.Database.BeginTransactionAsync(
System.Data.IsolationLevel.Serializable,
cancellationToken);
try
{
var query = _dbContext.ValidationRequests
.Where(vr => vr.State == Statuses.New)
.OrderBy(vr => vr.Id);
var response = await PagedList<Model>.GetPagedListAsync(
query,
page,
pageSize,
cancellationToken
);
await UpdateRangeAsync(response.Items, cancellationToken);
await transaction.CommitAsync(cancellationToken);
return response;
}
catch (Exception)
{
await transaction.RollbackAsync(cancellationToken);
throw;
}
以及更新方法:
private async Task UpdateRangeAsync(List<Model> requests, CancellationToken cancellationToken = default)
{
if (!requests.Any())
{
return;
}
requests.ForEach(item => item.State = Statuses.Pending);
_dbContext.UpdateRange(requests);
await _dbContext.SaveChangesAsync(cancellationToken);
}
您可以使用新的
ExecuteUpdateAsync
功能来执行连接的 UPDATE
语句。这意味着您不需要事务,因为无论如何整个语句都是原子的。
这样的东西会起作用,尽管我不完全清楚你的对象模型。
var baseQuery = PagedList<Model>
.Where(pl => pl.ValidationRequests
.Any(vr => vr.State == Statuses.New)
);
await baseQuery.ExecuteUpdateAsync(setters => setters
.SetProperty(item => item.State, Statuses.Pending,
cancellationToken);