C#将事务嵌套在循环中,但如果其中任何一个失败,则回滚
我试图解决的问题如下: 我有一个从文件中摄取数据并在多个表中插入某些内容的流程,就像现在一样,所有这些都是通过一个事务完成的,但是对于非常大的数据集,回滚或提交超时会失败,无论我将超时设置为什么(至少我所有的尝试都显示了这一点)。所以决定我需要重写功能来“切碎”任务。当前代码的伪代码类似于(用于避免不必要信息的伪代码) 正如我所说,这对于较小的数据集很好,但是当文件的行数超过特定数量(取决于超时)时,提交或回滚失败 例如,我不能仅仅将超时更改为10000秒,事实上,由于程序的结构方式,我根本不能出于测试目的更改超时。所以我想做的是让程序一次处理100行,而不是一次处理整个文件,提交它们,但是如果其中一个“百行集”失败,则回滚所有内容,我知道这可以通过嵌套事务来完成,但是这样做C#将事务嵌套在循环中,但如果其中任何一个失败,则回滚,c#,sql-server,transactions,transactionscope,rollback,C#,Sql Server,Transactions,Transactionscope,Rollback,我试图解决的问题如下: 我有一个从文件中摄取数据并在多个表中插入某些内容的流程,就像现在一样,所有这些都是通过一个事务完成的,但是对于非常大的数据集,回滚或提交超时会失败,无论我将超时设置为什么(至少我所有的尝试都显示了这一点)。所以决定我需要重写功能来“切碎”任务。当前代码的伪代码类似于(用于避免不必要信息的伪代码) 正如我所说,这对于较小的数据集很好,但是当文件的行数超过特定数量(取决于超时)时,提交或回滚失败 例如,我不能仅仅将超时更改为10000秒,事实上,由于程序的结构方式,我根本不能
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上遇到同样的问题吗>我相信你需要把事务提交到循环的底部(这将导致你需要考虑的其他问题(即如何回滚)。如果等待到内部事务循环之外,所有事务都将被捆绑并立即提交,这意味着性能实际上要比第一个示例的性能差得多
编辑:如前所述,这会导致一个问题,即如果一组插入失败,则无法回滚更改。要解决这个问题,我认为最简单的解决方案是创建一个“回滚”。在while循环中,您使用回滚到堆栈上所需的任何数据将某个对象推送到堆栈上。您添加了一个标志,以指示某项操作是否失败。如果出现故障,则切换标志并中断循环。然后弹出堆栈撤消更改,直到堆栈为空。然后您就知道数据库处于启动前的状态。之后,您可以从组1重试插入。或者,您可以添加重试逻辑以从组x继续,其中x是执行任何回滚之前失败的组。如果经过一定次数的重试后,未能完成完整插入,则进入回滚方法,在该方法中弹出堆栈直到为空 你好,谢谢你的回复。是的,我明白你说的表演是什么意思,但我可以牺牲表演,只要它真的做了我需要的。如果我在循环的底部提交事务,那么如果在某个点上其中一个集合失败,那么其余的仍然会通过,这就是我想要避免的。我需要他们全部加入,除非他们都没有失败。@A.D我意识到这一点,并找到了解决办法。然而,性能是阻止示例1运行的原因,因此,如果您尝试在内部循环之外提交,那么示例2永远不会起作用。我将编辑一个如何回滚的想法,它并不完全漂亮,但逻辑上是合理的。
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();
}