ABP UnitOfWork 没有为 IsolationLevel RepeatableRead 锁定数据库记录

ABP UnitOfWork is not locking database record for IsolationLevel RepeatableRead

这个问题最好能举例说明。我有一个数据库 table Person,其中有一个名为 [Num]int 列。它只有一条记录,初始值为Num == 0.

在我的PersonAppService.cs中,有以下2种方法

public void TestIncrementA()
{
    using (var uow = _unitOfWorkManager.Begin(new UnitOfWorkOptions { IsolationLevel = IsolationLevel.RepeatableRead })
    {
        var person = _personRepository.Get(1);
        person.Num += 1;

        Thread.Sleep(3000);

        uow.Complete();
    }
}

public void TestIncrementB()
{
    using (var uow = _unitOfWorkManager.Begin(new UnitOfWorkOptions { IsolationLevel = IsolationLevel.RepeatableRead })
    {
        var person = _personRepository.Get(1);
        person.Num += 1;

        uow.Complete();
    }
}

除了第一种方法延迟线程外,这 2 种方法本质上是相同的,它们将列 Num 的值递增。

现在在 Web 浏览器的控制台中,我 运行 快速连续执行以下命令。

abp.services.app.person.testIncrementA();
abp.services.app.person.testIncrementB();

我希望数据库中 Num 的值现在是 2,因为它已经增加了两次。然而它只是 1.

很明显 RepeatableRead UoW 没有正确锁定行。我也试过使用属性 [UnitOfWork(IsolationLevel.RepeatableRead)] 无济于事。

但是,如果我要在模块的 PreInitialize 中设置以下内容,它会起作用。

Configuration.UnitOfWork.IsolationLevel = IsolationLevel.RepeatableRead;

不幸的是,这将强制 Repeatable在整个应用程序范围内阅读。有什么我忽略的吗?

要设置与环境工作单元不同的隔离级别,请从另一个开始 RequiresNew:

using (var uow = _unitOfWorkManager.Begin(new UnitOfWorkOptions
{
    Scope = TransactionScopeOption.RequiresNew, // Add this
    IsolationLevel = IsolationLevel.RepeatableRead
})
{
    ...
}

说明

来自https://aspnetboilerplate.com/Pages/Documents/Unit-Of-Work

If a unit of work method calls another unit of work method, both use the same connection & transaction. The first entered method manages the connection & transaction and then the others reuse it.

The default IsolationLevel for a unit of work is ReadUncommitted if it is not configured. ...

Conventional Unit Of Work Methods

Some methods are unit of work methods by default:

  • ...
  • All Application Service methods.
  • ...