当前位置 : 主页 > 编程语言 > c语言 >

c# – 试图理解TransactionScope

来源:互联网 收集:自由互联 发布时间:2021-06-25
我正在尝试制作一个快速的虚拟应用程序,以便我可以了解System.Transactions的细节.此应用程序与2个不同的SQLExpress DB交互.如果我在组件服务中提取事务统计信息,我可以在打开第二个连接时
我正在尝试制作一个快速的虚拟应用程序,以便我可以了解System.Transactions的细节.此应用程序与2个不同的SQLExpress DB交互.如果我在组件服务中提取事务统计信息,我可以在打开第二个连接时看到在outerScope中启动事务.如果failOuter为true,则事务将中止,但不会抛出任何异常.当failInner为true时,抛出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()并处理任何结果异常,如果你想在事务失败时做一些特定的事情.

网友评论