代码之家  ›  专栏  ›  技术社区  ›  Dan H

打开和关闭事务内部的数据库连接

  •  9
  • Dan H  · 技术社区  · 14 年前

    我设计了框架的数据访问部分,这样每当业务对象(BO)需要与数据库交互时,它就必须打开一个连接,调用数据访问层(以执行查询),然后关闭连接。然后,如果需要在事务中运行,它将打开连接,开始事务,调用数据访问层(以执行查询),然后提交事务,关闭事务,最后关闭连接。

    我这样做是出于 “晚开门,早关门” _但是如果我需要打电话给其他BOS在一个事务中提交数据怎么办?是否有更好的方法来处理打开和关闭连接以及处理事务?

    我是设计应用程序体系结构的新手,所以我希望我没有做错事,任何帮助都会得到赞赏。

    5 回复  |  直到 12 年前
        1
  •  5
  •   Thomas    12 年前

    如果给定的业务对象需要在事务中执行各种方法,请使用 TransactionScope 像这样:

    using ( var transactionScope = new TransactionScope() )
    {
        this.Save();
        childObjA.Save();
        childObjB.Save();
        childObjC.Save();
        childObjD.Save();
    
        transactionScope.Complete();
    }
    

    如果任何对象抛出异常,它将回滚事务。

    the MSDN reference page for TransactionScope 更多信息。

        2
  •  4
  •   Aaronaught    14 年前

    当更高级别的抽象依赖于较低级别的抽象(例如依赖于数据连接的业务逻辑类)时,通常通过构造函数提供较低级别的抽象。这项技术被称为 构造注入 :

    public class OrderService
    {
        private SqlConnection connection;
    
        public OrderService(SqlConnection connection)
        {
            if (connection == null)
                throw new ArgumentNullException("connection");
            this.connection = connection;
        }
    
        // Other methods
    }
    

    这样,您就可以针对服务编写类似于以下内容的代码:

    using (TransactionScope tsc = new TransactionScope())
    using (SqlConnection connection = new SqlConnection(...))
    {
        connection.Open();
        OrderService os = new OrderService(connection);
        os.ProcessOrder(myOrder);
        ShippingService ss = new ShippingService(connection);
        ss.ShipOrder(myOrder);
        tsc.Complete();
    }
    

    最终,这很可能是您想要的——在多个服务之间共享一个连接的能力。

    这也有助于 解耦 您的服务来自数据连接的实现细节。这样,如果您想在某些情况下更改连接设置,您不必深入了解50个不同服务的详细信息,只需更改创建连接的一行代码。

    还有一件事:如果你要使用 TransactionScope ,确保添加 Transaction Binding=Explicit Unbind 到连接字符串,否则,如果事务超时,实际上可能会以不一致的数据结束。

        3
  •  2
  •   Randy Levy    14 年前

    正如其他人提到的, TransactionScope 是前进的道路。

    如果您使用的是SQL Server 2008和.NET 3.5,我将修改设计,使业务对象控制事务,并保留到数据层的连接的打开和关闭。

    打开连接池后,实际上不会产生打开物理数据库连接的开销,并且只有在执行实际工作时才能打开连接。自从(我猜)你 SQL Server 2008 with .NET 3.5 your transaction will not escalate to a distributed transaction (除非你同时打开多个连接),这样你就可以得到两个世界中最好的。

    然后您可以这样编写业务对象:

    using (TransactionScope transactionScope = new TransactionScope())
    {
        DataObject dataObject = new DataObject();
        dataObject.UpdateQuantity(...);
    
        ShippingManager shippingManager = new ShippingManager();
        shippingManager.ShipOrder(...);
    
        transactionScope.Complete()
    }
    

    这样可以避免将连接字符串传递给所有业务对象,并使协调事务变得容易。

    更新

    System.Transactions的优点在于,无论您使用的连接是什么,都可以为您管理所有事务。您只需声明一个TransactionScope,该TransactionScope中的所有数据库访问都将在一个事务中进行(除非您使用不同的TransactionScope设置另外请求)。

    在过去(SQL Server 2005.NET 2.0),如果打开和关闭了一个连接,然后打开和关闭了另一个连接(即使具有相同的连接字符串),则该事务将从轻量级事务升级为分布式事务。这是不可取的,因为性能受到影响(与MSDTC的通信不在进程中,并且是两阶段提交协议),并且在许多生产环境(防火墙和安全性)中配置MSDTC可能会很困难。

    在SQL Server 2008和.NET 3.5中,它们添加了在单个事务中打开和关闭具有相同连接字符串的多个连接时避免此提升的功能。对他们所看到的事情有一个很好的解释 Extending Lightweight Transactions in SqlClient .

    更新2

    使用Oracle 10g的事务将在TransactionScope中正常运行。看起来像 ODP.NET supports Lightweight Transactions (这很好)。不幸的是,我认为随着连接的关闭和打开,将升级到分布式事务。

    如果希望避免分布式事务,可以将连接传递给每个方法调用/业务对象。如果不想传递连接,可以使用 ConnectionScope class 使连接在线程上保持打开状态。另一种方法是使用EnterpriseLibrary3.0(及更高版本)数据访问应用程序块。这个 Data Access Block can detect that a transaction is in progress and use the same connection 以避免分布式事务。

        4
  •  2
  •   stakx - no longer contributing Saravana Kumar    12 年前

    听起来你的想法是对的。如果需要涉及多个bos,那么其中一个需要是一个“控制器”——它应该打开和关闭连接,并将其传递给其他人。或者一些“包装器”对象可以处理连接并将其传递给每个bos。您的bos可能需要设计为同时独立运行(处理自己的连接),并接受来自外部的现有连接。

        5
  •  1
  •   jrista    14 年前

    你可能在找 Unit of Work 模式和 Registry 模式。这两种模式可以协同工作,以分离查找业务对象和跟踪它们的关注点,以便以后将它们作为事务提交到数据存储中。

    我还将研究对象关系映射,或ORM。ORM是工作单元、注册表、持久性忽略和其他模式的更高级别的组合,它提供了业务逻辑与持久性逻辑的非常清晰的分离。使用和ORM,通常可以消除编写存储过程、构建自定义DAL等的需要。ORM为您处理持久性问题,使您能够专注于需要完成的业务逻辑。

    因为您使用的是C和.NET,所以我将研究实体框架(v4,不使用v1)或linq-to-sql。两者都是或映射器,从v3.5及以后的.NET框架提供。LinqtoSQL是一个非常简单且工具完善的ORM,它可以让您快速地进行工作。实体框架是一个更丰富的ORM,它也是非常好的工具(比Linq to SQL更好),并且提供了更多的功能。还有第三方ORM可以完成这项工作,包括一个名为nhibernate的免费ORM。虽然它的工具不如微软的ORM那么好,但nhibernate是一个非常成熟的开源ORM,拥有大量的社区追随者。

    如果没有ORM,我会调查 工作单位 , 登记处 (或知识库),持续的无知, Separation of Concerns , Single Responsibility 以及其他相关模式。