嵌套的TransactionScope()不会回滚

时间:2014-03-28 08:43:30

标签: c# sql transactions

我是第一次尝试在C#中使用嵌套事务。在过去,我始终将SqlCommands包裹在SqlTransactions SqlConnections内。像这样:

using (SqlConnection myCon = new SqlConnection(...))    
    using (SqlTransaction myTran = myCon.BeginTransaction())
    {
        using (SqlCommand myCom1 = new SqlCommand("...", myCon, myTran))
        {
            ...
        }       
        using (SqlCommand myCom2 = new SqlCommand("...", myCon, myTran))
        {
            ...
        }
        .
        .
        .
        myTran.Commit();
    }
}

所有这些,当然需要try...catch处理,所以如果SqlTransaction内的任何地方发生异常,我知道SqlCommands都不会被提交。

所以我想我会尝试使用TransactionScope,但它不起作用。这就是我正在做的事情;我有两个交易,一个接一个,但都在外部交易中。根据在表单上检查的复选框,代码会抛出异常: 1.在第一个内部交易提交之前,或者 2.两个内部交易之间,或 3.在第二个内部事务的提交之前,或者 4.就在外部事务的提交之前

我遇到的问题是,无论我勾选哪个复选框,代码都会执行,就像没有任何交易一样。换句话说,我因为异常而跳出try块的事实不会回滚任何事务。

会感激一些帮助。下面是我的小测试应用程序的代码。

try
{
    using (SqlConnection sqlConnection = new SqlConnection(connectionString))
    {
        sqlConnection.Open();

        using (TransactionScope transactionOuter = new TransactionScope())
        {
            using (TransactionScope transactionInner1 = new TransactionScope())
            {
                using (SqlCommand sqlCommand = new SqlCommand("INSERT INTO BasicTable (Value) VALUES ('Inside Inner Transaction 1')", sqlConnection))
                {
                    sqlCommand.ExecuteNonQuery();
                }

                if (checkBox_FailInner1.Checked)
                    throw (new Exception("Failed inside inner transaction 1"));

                transactionInner1.Complete();
            }

            if (checkBox_FailBetween.Checked)
                throw (new Exception("Failed between inner transactions"));

            using (TransactionScope transactionInner2 = new TransactionScope())
            {
                using (SqlCommand sqlCommand = new SqlCommand("INSERT INTO BasicTable (Value) VALUES ('Inside Inner Transaction 2')", sqlConnection))
                {
                    sqlCommand.ExecuteNonQuery();
                }

                if (checkBox_FailInnner2.Checked)
                    throw (new Exception("Failed inside inner transaction 2"));

                transactionInner2.Complete();
            }

            if (checkBox_FailOuter.Checked)
                throw (new Exception("Failed before outer transaction could commit"));

            transactionOuter.Complete();
        }
    }
}
catch (Exception exc)
{
    MessageBox.Show(exc.Message);
}

MessageBox.Show("Done");

1 个答案:

答案 0 :(得分:2)

SqlConnection在打开时会自行登记。只有这个时间点很重要。该连接将被登记到当时处于活动状态的任何事务中。您在安装任何事务之前打开连接。

我相信你有第二个误解:无法嵌套交易。您只能嵌套范围。回滚内部作用域时,将回滚整个事务。所有TransactionScope都设置并操作Transaction.Current。而已。最外面的作用域安装一个事务。内部范围大多是无操作。他们所做的就是提供一种通过不完成交易来完成交易的方法。