使用SqlTransactions混合System.Transactions

Wes*_*son 5 c# sql-server asp.net ado.net

今天晚上我一直在汲取我的知识,试图克服4年糟糕的编程习惯,因为我正在为之工作.我最近偶然发现的一件事是System.Transactions.在阅读了最近几个小时之后,我想我已经充分了解它们的工作原理以及为什么要使用它们.但是,我所看到的所有示例都显示了在事务中调用的内联T-SQL.

在进行数据库访问时,我几乎只使用存储过程,现有的存储过程都包含在自己的SqlTransactions中.你知道,使用'Begin Tran'然后回滚或提交.如果存储过程调用另一个存储过程,它也会创建一个事务,并且Commits会冒泡,直到外部提交或回滚.效果很好.

所以现在我的问题是,如果我想在我的代码中开始使用System.Transactions - 为了监控不能嵌套在单个存储过程中的连续数据库任务的简单目的 - 它如何与现有的SqlTransactions一起工作我已经我的存储过程中有什么?

在我的代码中使用System.Transactions只是在实际提交之前添加了一层保护,或者因为我在我的SqlTransaction中明确提交 - 无论是在基于代码的事务中提交还是回滚,数据都会被保留吗?

Bil*_*eau 5

不,System.Transactions和Sql事务不混合.

我引用以下MSDN文章中的"不要混合它们":https://msdn.microsoft.com/en-us/library/ms973865.aspx.

Sql事务不以您希望的方式参与外部System.Transaction.失败或回滚的Sql事务不会导致System.Transaction中的其他活动回滚.


这个例子说明了这种现象:

using (var tx = new TransactionScope())
{
    using (var con = new SqlConnection($"{connectionstring}"))
    {
        con.Open();

        using (var com = new SqlCommand($"set xact_abort on; begin transaction; INSERT INTO dbo.KeyValueTable VALUES ('value1', '{Guid.NewGuid()}'); rollback;", con))
        {
            // This transaction failed, but it doesn't rollback the entire system.transaction!
            com.ExecuteNonQuery();
        }

        using (var com = new SqlCommand($"set xact_abort on; begin transaction; INSERT INTO dbo.KeyValueTable VALUES ('value2', '{Guid.NewGuid()}'); commit;", con))
        {
            // This transaction will actually persist!
            com.ExecuteNonQuery();
        }
    }
    tx.Complete();
}
Run Code Online (Sandbox Code Playgroud)

在空数据存储上运行此示例后,您应该注意到第二个Sql操作中的记录确实已提交,而C#代码的结构意味着它们不应该是.


简而言之,你不应该混合它们.如果您在应用程序中编排多个Sql事务,则应该只使用System.Transactions.不幸的是,这意味着从您的所有存储过程中删除您的事务代码,但是,有必要像混合模型一样,您无法保证数据的完整性.