SQL事务:在ASP.Net中实现的最佳方式

4
我有一个应用程序,其中有许多不同类型的对象,每个对象都会将自己持久化到数据库中。目前没有使用事务,这一直运行得很好,我也不想大费周折地添加它们。但是偶尔需要在整个对象集开始更新之前启动一个事务,以确保只有所有对象都成功后才实际更新数据库。

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

我遇到的问题是,每次更新现在都是原子性的(没有明确包装在事务中)。我可以向每个“苹果”传递一个ID来标识已经存储在某种缓存中的事务,但那么就存在缓存可能在更新过程中失效并导致不必要问题的风险。

那么,最好的方法是什么?
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接口,因此当using调用Dispose()时,如果从未调用Complete(),事务将回滚。使用TransactionScope需要启用分布式事务协调器。


并不总是,但它极大地简化了事情。 - Jason Jackson
需要启用DTC时,更好的参考资料在这里:http://msdn.microsoft.com/en-us/library/ms229978.aspx - Martin Brown

1

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

阅读{{link1:MSDN}}上的所有内容:

Transaction Flow Management

Transaction scopes can nest both directly and indirectly. A direct scope nesting is simply one scope nested inside another, as shown in Example 5.

Example 5. Direct scope nesting

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

An indirect scope nesting occurs when calling a method that uses a TransactionScope from within a method that uses its own scope, as is the case with the RootMethod() in Example 6.

Example 6. Indirect scope nesting

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();
   }
}

1

楼主说这个集合管理了事务中所有其他对象的保存,因此在这里放置事务代码似乎是显而易见的。如果您正在使用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();
        }            
    }
}

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中处理事务,我相信他们知道该怎么做。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接