It's better if this issue is explained with an example. I have a database table Person
with an int
column named [Num]
. It has only a record with the initial value of Num
== 0.
In my PersonAppService.cs, there are the following 2 methods
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();
}
}
The 2 methods are essentially the same which increment the value of the column Num
by one except that the first method delays the thread.
Now in the console of a web browser, I run the following commands in quick succession.
abp.services.app.person.testIncrementA();
abp.services.app.person.testIncrementB();
I would expect the value of Num
in my database to be 2 now since it's been incremented twice. However it's only 1.
It's clear the RepeatableRead
UoW is not locking the row properly. I have also tried using the attribute [UnitOfWork(IsolationLevel.RepeatableRead)]
to no avail.
But, if I were to set the following in the PreInitialize
of a module, it works.
Configuration.UnitOfWork.IsolationLevel = IsolationLevel.RepeatableRead;
This will unfortunately force RepeatableRead app-wide. Is there something that I'm overlooking?
To set a different isolation level from the ambient unit of work, begin another with RequiresNew
:
using (var uow = _unitOfWorkManager.Begin(new UnitOfWorkOptions { Scope = TransactionScopeOption.RequiresNew, // Add this IsolationLevel = IsolationLevel.RepeatableRead }) { ... }
From 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.
- ...