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.
- ...
这个问题最好能举例说明。我有一个数据库 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 isReadUncommitted
if it is not configured. ...Conventional Unit Of Work Methods
Some methods are unit of work methods by default:
- ...
- All Application Service methods.
- ...