共享 IDbConnection 以保持事务本地化

Posted

技术标签:

【中文标题】共享 IDbConnection 以保持事务本地化【英文标题】:Share IDbConnection to keep transaction local 【发布时间】:2016-04-27 14:06:15 【问题描述】:

Data Repository,它处理从通用接口继承的数据实体,DAL 层被实现为通用类,它以依赖注入的形式获取通用接口。以下是设计:

数据实体 - 车辆

public class Vehicle

    public int Id get; set;

    public string Brand get; set;

通用接口 - IData

public interface IData<T>

   IEnumerable<T> Select(IDictionary<string,object> parameters);

   int Update(IDictionary<string,object> parameters);

   int Delete(IDictionary<string,object> parameters);

   int insert(IDictionary<string,object> parameters);

车辆存储库

public class VehicleData : IData<Vehicle>

   IEnumerable<Vehicle> Select(IDictionary<string,object> parameters)
   
      using(IDbConnection conn = (Fetch Connection))
      
         // Select Operation
       
   

   int Update(IDictionary<string,object> parameters)
    
      using(IDbConnection conn = (Fetch Connection))
      
         // Update Operation
       
   

   int Delete(IDictionary<string,object> parameters)
    
      using(IDbConnection conn = (Fetch Connection))
      
         // Delete Operation
       
   

   int insert(IDictionary<string,object> parameters)
    
      using(IDbConnection conn = (Fetch Connection))
      
         // Insert Operation
       
   

DAL 类实现:

public class DAL<T>

  public static IEnumerable<T> Select(IData<T> dataRepository, IDictionary<string,object> parameters)
   
       return dataRepository.Select(parameters);
   

// Implementation for Insert, Update and Delete

我使用调用类中的DAL 执行VehicleData,如下所示。

IData<Vehicle> vehicleData = new VehicleData();

IDictionary<string,object> parameters = // Filled from client

DAL<Vehicle>.Select(vehicleData,parameters);

我面临的问题是,在每个 CRUD 方法中,IDbConnection 都是在 Using 块中创建的,因此在最后处置,因为它在本地上下文中,但是有一种情况,需要对各种实体进行多个 DAL 操作成为单个事务上下文的一部分,如果我以类似的方式继续,那么打开的事务上下文将被提升到分布式级别,因为多个连接资源正在打开,即使我可以在相同的连接上下文上执行它们,因为它们被一一执行。问题仍然存在:

    如何在DAL&lt;Vehicle&gt;.Update, DAL&lt;Driver&gt;.Update and DAL&lt;Truck&gt;.Update等多个调用之间共享连接,从而避免事务从本地升级到分布式

    不确定,在事务上下文中打开和处理连接是否意味着可以打开另一个连接而无需提升到分布式事务,在我看来这不会发生

【问题讨论】:

【参考方案1】:

您是否使用 IoC 容器进行依赖注入?在 IoC 中有一些生活方式(每个线程、每个 Web 请求等)。例如,对于城堡温莎,您可以使用 Scoped lifestyle。你的代码会是这样的:

创建连接(linq2db):

container.Register(
    Component.For<DataConnection>().UsingFactoryMethod(x => 
        CreateDataConnection()).LifestyleScoped(),
    Component.For<IData<Vehicle>>()
        .ImplementedBy<VehicleData>().LifestyleScoped()
);

private static DataConnection CreateDataConnection()

    return new DataConnection(new SqlServerDataProvider("", SqlServerVersion.v2008), 
        @"Data Source=(local);Initial Catalog=DB1;Persist Security Info=True;User ID=user;Password=pwd");

做一些数据库操作:

using (container.BeginScope())

    var db = container.Resolve<DataConnection>();
    db.BeginTransaction();
    container.Resolve<IData<Vehicle>>().Update(...);
    container.Resolve<IData<Vehicle>>().Update(...);
    container.Resolve<IData<Vehicle>>().Update(...);
    db.CommitTransaction();

【讨论】:

这不是我的问题陈述的确切解决方案,但它确实为我提供了开始将 IDbConnection 作为参数并从调用者相同的连接传递的线索,特别是因为我更喜欢 TransactionScope 而不是 IDbConnection ,您的解决方案只是使 Container 上下文对所有调用都通用,但感谢您的提醒

以上是关于共享 IDbConnection 以保持事务本地化的主要内容,如果未能解决你的问题,请参考以下文章

Net Core中数据库事务隔离详解——以Dapper和Mysql为例

注入连接字符串与 IDbConnection

数据库操作事务IsolationLevel 枚举

sqlsugar怎么判断插入失败

SQLServer之创建不可重复读

sqlsugar 支不支持linq