在Web应用程序中使用TransactionScope是否安全?

时间:2013-12-16 07:42:30

标签: c# asp.net transactions transactionscope

在Web应用程序中使用TransactionScope时,我遇到了一个很大的问题:

我有一个Web应用程序,它有一些使用事务的方法:

public class ProductsService
{
    private readonly ProjectDbContext _db;
    public ProductsService(ProjectDbContext db)
    {
        _db = db;
    }

    public void DelteProduct(Guid product_Id)
    {
        Product product = _db.Products.First(p => p.Id == product_Id);

        using (TransactionScope ts = new TransactionScope())
        {
            // Delete comments
            _db.SaveChanges();

            // Delete subscriptions
            _db.SaveChanges();

            // Delete product
            _db.SaveChanges();

            ts.Complete();
        }
    }
}

在本地测试,我没有问题。

然而,当我将项目投入生产时,我随机得到SqlExceptionTransaction错误:

System.Data.SqlClient.SqlExceptionTransaction (Process ID 55) was deadlocked on lock resources with another process and has been chosen as the deadlock victim.
Rerun the transaction.

我认为事务应该在队列中工作,并且新事务应该等到提交旧事务,并且不阻止它们 - 即使发生错误。

  1. 为什么我收到此错误?
  2. 我应该在网络应用程序中完全避免使用交易吗?
  3. 我使用TransactionScope错了?

1 个答案:

答案 0 :(得分:0)

  

我认为事务应该在队列中工作,并且新事务应该等到提交旧事务,并且不阻止它们 - 即使发生错误。

交易排队,但仅限于可能。当两个事务彼此等待时发生死锁;两者都持有对方所需的资源。有很多文章描述了死锁以及它们如何在数据库中出现。

  

为什么我收到此错误?

如果要查看导致死锁的原因,可以对数据库进行概要分析并分析死锁图(https://www.simple-talk.com/sql/learn-sql-server/how-to-track-down-deadlocks-using-sql-server-2005-profiler/)。总的来说,我会避免使用TransactionScope默认构造函数,因为它将事务级别设置为序列化(http://blogs.msdn.com/b/dbrowne/archive/2010/05/21/using-new-transactionscope-considered-harmful.aspx)。

来自文章:

  

在SQL Server中,SERIALIZABLE事务很少有用且极易出现死锁。换句话说,当默认的READ COMMITTED隔离级别没有提供正确的隔离语义时,SERIALIZABLE很少会更好,并且经常会引入严重的阻塞和死锁问题。“


  

我是否应该避免在网络应用程序中使用交易?“

无论如何,没有。事务应该用于定义原子操作,必须提交的事项应该在一个事务中运行。在回顾中,Web应用程序没有什么特别之处,但是:停止使用默认构造函数。

  

我使用TransactionScope错了吗?“

正如我上面所解释的:是的,避免使用默认构造函数并具体说明您的事务级别; “序列化”永远不是正确的答案