c# - 试图了解 TransactionScope

标签 c# transactions transactionscope

我正在尝试制作一个快速的虚拟应用程序,以便我可以了解 System.Transactions 的来龙去脉。此应用程序与 2 个不同的 SQLExpress 数据库交互。如果我在组件服务中提取我的事务统计信息,我可以看到在打开第二个连接时在 outerScope 中启动了一个事务。如果 failOuter 为真,事务将中止,但不会抛出任何异常。当 failInner 为真时,将抛出 TransactionAbortedException。

From MSDN:

When your application completes all the work it wants to perform in a transaction, you should call the Complete method only once to inform the transaction manager that it is acceptable to commit the transaction. It is very good practice to put the call to Complete as the last statement in the using block.

Failing to call this method aborts the transaction, because the transaction manager interprets this as a system failure, or equivalent to an exception thrown within the scope of transaction.

A TransactionAbortedException is thrown if the scope creates the transaction, and the transaction is aborted.

基于此,我希望我的 outerScope 抛出一个 TransactionAbortedException,因为每次我运行我的应用程序并将 failOuter 设置为 true 时,我的事务统计信息都会显示一个中止的事务。我的方法返回 true,因为即使事务中止也不会抛出异常。除非我中止内部事务,否则它会按我的预期运行。任何澄清将不胜感激。

public bool CreateNestedTransaction(bool failOuter, bool failInner)
    {
        try
        {
            using (TransactionScope outerScope = new TransactionScope())
            {

                /* Perform transactional work here */
                using (SqlConnection myConnection = new SqlConnection("server=(local)\\SQLExpress;Integrated Security=SSPI;database=test1"))
                {
                    SqlCommand myCommand = new SqlCommand();
                    myConnection.Open();
                    myCommand.Connection = myConnection;

                    myCommand.CommandText = "update test set Value = ((select Value from test where Id = (select max(Id) from test))+1) where Id = (select max(Id) from test)";
                    myCommand.ExecuteNonQuery();
                }


                using (SqlConnection myConnection = new SqlConnection("server=(local)\\SQLExpress;Integrated Security=SSPI;database=test1"))
                {
                    SqlCommand myCommand = new SqlCommand();
                    myConnection.Open();
                    myCommand.Connection = myConnection;

                    myCommand.CommandText = "update test set Value = Value";
                    myCommand.ExecuteNonQuery();
                }

                using (TransactionScope innerScope = new TransactionScope())
                {
                    using (SqlConnection myConnection = new SqlConnection("server=(local)\\SQLExpress;Integrated Security=SSPI;database=test2"))
                    {
                        SqlCommand myCommand = new SqlCommand();
                        myConnection.Open();
                        myCommand.Connection = myConnection;

                        myCommand.CommandText = "update test set Value = ((select Value from test where Id = (select max(Id) from test))+1) where Id = (select max(Id) from test)";
                        myCommand.ExecuteNonQuery();
                    }
                    if (failInner == false) { innerScope.Complete(); }
                }

                if (failOuter == false) { outerScope.Complete(); }
            }
        }

        catch (TransactionAbortedException)
        {
            return false;
        }

        return true;
    }

最佳答案

通常,在 TransactionScope 超出范围并被处置之前,您不会因未能调用 TransactionScope.Complete() 而引发异常。事务将悄悄回滚。

在您的案例中发生异常是因为您试图在外部 TransactionScope 上调用 Complete 并且它无法正确完成,因为内部 TransactionScope 已经失败 - 因此这会引发异常。

这有意义吗?

如果你想在你的外部事务中止时执行一些操作,你可以尝试这样的事情:

// Inside each using TransactionScope(), hhok up the current transaction completed event
Transaction.Current.TransactionCompleted += new TransactionCompletedEventHandler(Current_TransactionCompleted);

// handle the event somewhere else
void Current_TransactionCompleted(object sender, TransactionEventArgs e)
{
  //  check the status of the transaction
  if(e.Transaction.TransactionInformation.Status == TransactionStatus.Aborted)
    // do something here
}

虽然我认为更简洁的通用模式是始终在您的 TransactionScope 中调用 Complete() 并处理任何由此产生的异常,如果您想对事务失败执行特定的操作。

关于c# - 试图了解 TransactionScope,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/787052/

相关文章:

C# svnadmin 转储,奇怪的行为

c# - 使用 C# 的 SqlConnection 错误 vs2015

java - 无法填充池(没有可用的缓冲区空间)

PHP 和 MySQLi 检查是否在事务中

C# 泛型不允许委托(delegate)类型约束

c# - 运行 XUnit 测试时 CefSharp 的 FileNotFoundException

node.js - 具有单个数据库的多个 Node 实例

C# - 业务层事务的使用(SQLServer 2005+,Oracle) - 很好的例子

c# - 使用 System.Transactions 时保存点的替代方法

c# - 交易范围和手动定义的交易之间的区别?