C#循环中的嵌套事务,但如果其中任何一个失败则回滚

时间:2013-05-02 16:08:09

标签: c# sql-server transactions transactionscope rollback

我想解决的问题如下:

我有一个进程从文件中提取数据并在多个表中插入某些内容,因为现在它完全由一个事务完成,但是对于非常大的数据集,回滚或提交超时并失败,没有无论我把时间设定为什么(至少就我的所有尝试都表明的那样)。所以决定我需要重写功能来“完成”任务。因为它当前代表当前代码的伪代码看起来像(用于避免不必要信息的伪代码)

variable = FunctionThatReadsFromAFile();

ITransactionManager transactionObject = new TransactionManager();
IDbTransaction dbTransaction = transactionObject.Get();

WriteToFirstTable(variable ,dbTransaction);
WriteToSecondtable(variable ,dbTransaction);
WriteToThirdTable(variable ,dbTransaction);

if(!Error)
transactionObject.Commit(dbTransaction);
else
transactionObject.Rollback(dbTransaction);

就像我说的,这适用于较小的数据集,但是当文件具有超过特定数量的行(取决于超时)时,它在提交或回滚时失败。

例如,我不能只将时间更改为10,000秒,实际上由于程序的结构方式,我无法在测试时将时间更改为超出时间。所以我要做的是让程序一次运行100行,而不是一次完成整个文件,提交它们,但如果其中一个“数百套”失败,那么就回滚所有内容,我明白了这可以通过嵌套事务完成,但这样做;

using (TransactionScope outterTransaction = new TransactionScope())
{

    while(file.read()) 
    {

        using (TransactionScope innerTransaction = new TransactionScope())

        {

        variable = GetNextHundredOrLessRows(file); //100 rows at a time basically

        WriteToFirstTable(variable ,innerTransaction );

        WriteToSecondtable(variable ,innerTransaction );

        WriteToThirdTable(variable ,innerTransaction);


        if(!Error)
        innerTransaction.Complete();
        else
        innerTransaction.Rollback();

        }

    }

    if(!Error)
        outterTransaction.Complete();
        else
        outterTransaction.Rollback();

}

不工作,知道我做错了什么?

先谢谢大家抽出时间试图帮助我。

编辑:这也是解决问题的正确方法吗?我已经读过嵌套事务加入外部事务的范围,所以我仍会在.Complete上遇到同样的问题吗?

1 个答案:

答案 0 :(得分:0)

我认为你需要在循环的底部提交事务(这将导致你需要考虑的其他问题,即如何回滚)。如果您等到内部事务循环之外,所有事务将立即捆绑并提交,这意味着性能实际上将远远低于第一个示例的性能。

编辑:如上所述,这会导致一个问题,即如果一组插入失败,则无法回滚更改。为了解决这个问题,我认为最简单的解决方案是创建一个“RollBackStack”。在while循环中,你可以用一些回滚到堆栈所需的数据来推送一些对象。您添加一个标志以指示某些内容是否失败。如果发生故障,则切换标志并从循环中断。然后弹出堆栈撤消更改,直到堆栈为空。然后,您知道db处于启动之前的状态。之后,您可以从组1重试插入。或者,您可以添加重试逻辑以从组x继续,其中x是在执行任何回滚之前失败的组。如果经过一定次数的重试后,您无法完成完整插入,则进入回滚方法,在该方法中将堆栈弹出为空。