业务层中的事务范围,用于脏异步读取



我正在开发一个.NET Core Web api服务,并在BL中使用以下方法:

public async Task<SetParams> GetParams(CreateRequest request)
{
var user = await _userRepository.GetUserByLogin(request.Login);  
var client = await _clientRepository.GetClientByCode( request.ClientCode);
// many other getters here 
return new SetParams
{
IdUser = user.IdUser,
ClientName = client.Name,
// and so forth...
};
}

我需要让所有实体处于"脏读"模式。

因此,我尝试以这种方式使用TransactionScope:

public async Task<SetParams> GetParams(CreateRequest request)
{
using (var ts = new TransactionScope(
TransactionScopeOption.Required,
new TransactionOptions { IsolationLevel = IsolationLevel.ReadUncommitted }))
{
var user = await _userRepository.GetUserByLogin(request.Login);
var client = await _clientRepository.GetClientByCode(request.ClientCode);
// many other getters here 
ts.Complete();
return new SetParams
{
IdUser = user.IdUser,
ClientName = client.Name,
// and so forth...
};
}
}

但是:1(这已经读取了提交模式(我从这篇文章中知道我必须开始交易,但我在这里没有会话或数据库上下文,因为我在BL中而不是在DAL中(

和 2( 以异常结束事务范围必须在创建它的同一线程上释放。

您需要读取查询集的事务(脏读取(

我假设您具有高并发性来读取未提交的数据。这可能是在选择查询中使用事务的唯一用例。我认为它们仍然与少数 DML 操作交织在一起

从哪里开始交易,BL/DAL,它需要DbContext吗?

这取决于您的用例,如果您的设计使得从 BL 调度多个业务查询(应是事务的一部分(,那么它是一个有效的起点,尤其是使用环境事务 (TransactionScope(。启动事务的显式SessionContext是机制之一,因为所有共享查询都无缝地登记在同一事务上下文中,但是使用TransactionScopeCommittableTransaction也可以进行类似的事情,您可以利用TransactionScopeOption来确保参与各种查询:

使用Requires New在 BL 级别启动环境事务,并使用
  1. Required在 DAL 级别启动环境事务,以确保注册使用相同的事务上下文。数据库连接应在可用范围内自动登记。
  2. 使用CommittableTransaction,在 BL 中创建的相同对象被传递到 DAL 存储库,并且在那里显式登记连接对象
  3. 如果你的要求更具体一点,在单独线程上的所有子操作完成之前,"无提交"是可行的,那么请查看 DependantTransaction,它也是 System.transaction 的一部分,但它执行了更紧密的绑定,主要用于多线程方案,你可能不需要它来进行异步等待调用, 因为只有当所有awaits都完成后,您才能完成。

与事务范围相关的问题必须在创建它的同一线程上处理。

解决方案在这里,这是在 .Net4.5.1 并确保跨异步调用使用TransactionScope

查询的 SQL 服务器隔离级别

您指的是大多数系统ReadCommitted的默认值,但您当然可以调整设置以确保较低的隔离级别,但也要准备好在应用程序中读取脏数据的含义

最新更新