4

我有一个应用程序,它有许多不同类型的对象,每个对象都将自己持久化回数据库。到目前为止,这在没有交易的情况下运行良好,我不想疯狂添加它们。但是偶尔需要在整个对象集合开始更新之前启动事务,以确保只有在集合中的所有对象都成功时才真正更新数据库。

例如,假设我有一组苹果。向集合发出命令以更新所有苹果。[事务开始应该在这里] 每个苹果执行代码来更新自己。[事务提交/回滚应该在这里发生]。

我遇到的问题是每个更新现在都是原子的(没有明确地包装在事务中)。我可以将一个 id 传递给每个“苹果”,以识别已隐藏在某种缓存中的事务,但是存在缓存在更新过程中失效并导致不必要问题的风险。

那么最好的方法是什么?

4

4 回答 4

4

首先,我不会处理页面中的事务逻辑。编写某种业务类来执行此操作 - 服务、数据实用程序类,您可以从 ASP.Net 中抽象出来的东西。

接下来,如果您使用可以订阅分布式事务的数据库(如 SQL Server) ,您可能会考虑使用TransactionScope类(在 System.Transactions 命名空间中,参考 System.Transactions.dll)。

using(TransactionScope scope = new TransactionScope())
{
  SaveObjectOne(); //these are just psuedo-code statements
  SaveObjectTwo(); //replace these with your code that saves various objs
  SaveObjectThree();
  scope.Complete(); //this commits the transaction, unless exception throws
}

TransactionScope 实现 IDisposable,因此当使用调用Dispose()时,如果Complete()从未调用过,事务将回滚。您确实需要启用分布式事务协调器才能使用TransactionScope

于 2008-11-24T02:12:43.530 回答
1

OP 说该集合管理事务中所有其他对象的保存,因此将事务代码放在这里似乎很明显。如果您使用的是 ADO.Net,打开连接并在集合中开始事务,然后将其传递给其他每个对象,这似乎是最简单的选择。我假设这里的每个对象都继承自层超类型类,并且您使用的是 SQL Server。

public void Save()
{
    using (SqlConnection connection = new SqlConnection("Connection String"))
    {
        using (SqlTransaction trans = connection.BeginTransaction())
        {
            foreach (BusinessObject obj in this) 
            { 
                obj.Save(connection); 
            } 
            trans.Commit();
        }            
    }
}
于 2008-11-24T10:19:52.720 回答
1

ado.net 2.0 中的事务非常简单,我建议使用 transactionscope 并让框架为您管理事务:

在 MSDN 上阅读所有相关信息:

交易流管理

事务范围可以直接嵌套也可以间接嵌套。直接范围嵌套只是一个范围嵌套在另一个范围内,如示例 5 所示。

示例 5. 直接范围嵌套

using(TransactionScope scope1 = new TransactionScope())
{
   using(TransactionScope scope2 = new TransactionScope())
   {
      scope2.Complete();
   }
   scope1.Complete();
}

TransactionScope当在使用自己的范围的方法中调用使用 from 的方法时,会发生间接范围嵌套 ,如RootMethod()示例 6 中的情况。

示例 6. 间接范围嵌套

void RootMethod()
{
   using(TransactionScope scope = new TransactionScope())
   {
      /* Perform transactional work here */
      SomeMethod();
      scope.Complete();
   }
}

void SomeMethod()
{
   using(TransactionScope scope = new TransactionScope())
   {
      /* Perform transactional work here */
      scope.Complete();
   }
}
于 2009-10-13T16:46:57.250 回答
0
  1. 我更喜欢声明性事务而不是尝试进行手动数据库事务。
  2. 正如 Mitch Wheat 已经提到的,事务具有上下文并且是基于连接的,因此它将包括您在页面/方法中发生的更改,如果一切正常则提交,或者如果出现异常则回滚。
  3. 我在这里可能错了,但我感觉“页面事务”正在使用 .NET 1.1 中的企业服务模型并通过 MSDTC(分布式事务协调器,注册的 COM+ 服务)工作......
  4. 对于 .NET 2.0 中的声明性事务,我更喜欢 System.Transactions 和 LTM(轻量级事务管理器)
  5. 我更喜欢 Spring.NET 框架事务(适用于 ADO.NET 和 NHibernate 版本),因为我相信它们支持更好的基于 AOP(面向方面​​编程)的关注点分离,您不必将代码与事务代码耦合,主要是因为这些人多年来一直在使用 Java 进行交易,我相信他们知道该怎么做。
于 2008-11-24T01:26:26.027 回答