我正在开发.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)这已经读取了提交模式(我从this post知道我必须启动一个事务,但我这里没有会话或数据库上下文,因为我在BL中不在DAL中)
2)以异常结束必须将TransactionScope放置在创建它的同一个线程上。
您需要事务处理的Read查询集(脏读)
我假设你有很高的并发性来读取未提交的数据。这可能是在Select查询中使用事务的唯一用例。我认为它们仍然与少数DML操作交织在一起
从哪里开始Transaction,BL / DAL,它需要DbContext吗?
这取决于您的用例,如果您的设计是从BL分配多个业务查询(应该是事务的一部分),那么它是一个有效的起点,尤其是使用Ambient事务(TransactionScope)。用于启动事务的显式Session
或Context
是其中一种机制,因为所有共享查询都在同一个事务上下文中无缝地登记,但使用TransactionScope
或CommittableTransaction
可能类似,您可以使用TransactionScopeOption
来确保各种查询的参与:
Requires New
使用Required
在BL和DAL级别启动环境事务,以确保使用相同的事务上下文进行登记。数据库连接应自动登记在可用范围内。CommittableTransaction
,在BL中创建的同一对象被传递到DAL存储库,并且显式登记了Connection对象awaits
完成时才完成。与A TransactionScope相关的问题必须放在与其创建的同一个线程上。
解决方案是here,这是在.Net4.5.1中引入的,并确保在异步调用中使用TransactionScope
查询的SQL Server隔离级别
您所指的是大多数系统ReadCommitted
的默认设置,但您当然可以调整设置以确保更低的IsolationLevel,同时还要准备好在应用程序中读取脏数据的含义