在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.
我认为事务应该在队列中工作,并且新事务应该等到提交旧事务,并且不阻止它们 - 即使发生错误。
TransactionScope
错了?答案 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错了吗?“
正如我上面所解释的:是的,避免使用默认构造函数并具体说明您的事务级别; “序列化”永远不是正确的答案