我正在使用 C# 将发票平面文件导入到数据库中。如果遇到问题,我将使用 TransactionScope 回滚整个操作。
这是一个棘手的输入文件,因为一行不一定等于一条记录。它还包括链接记录。发票将包含标题行、行项目和总计行。有些发票需要跳过,但我可能不知道需要跳过,直到达到总行数。
一种策略是将标题、行项目和总行存储在内存中,并在达到总行后保存所有内容。我现在正在追求这个。
但是,我想知道是否可以用不同的方式来完成。围绕发票创建“嵌套”事务,插入标题行和行项目,然后在达到总行数时更新发票。如果确定需要跳过发票,则此“嵌套”事务将回滚,但整个事务将继续。
这可能、实用吗?您将如何设置?
最佳答案
TransactionScope
都不是SQL Server 也不支持嵌套事务。
你可以嵌套TransactionScope
实例,但仅具有嵌套事务的外观。实际上,存在一种称为“环境”事务的东西,并且一次只能有一个。哪个事务是环境事务取决于您的用途 TransactionScopeOption
当您创建范围时。
要更详细地解释,请考虑以下内容:
using (var outer = new TransactionScope())
{
DoOuterWork();
using (var inner1 = new TransactionScope(TransactionScopeOption.Suppress))
{
DoWork1();
inner1.Complete();
}
using (var inner2 = new TransactionScope(TransactionScopeOption.RequiresNew))
{
DoWork2();
inner2.Complete();
}
using (var inner3 = new TransactionScope(TransactionScopeOption.Required))
{
DoWork3();
inner3.Complete();
}
outer.Complete();
}
以下是每个内部作用域发生的情况:
inner1
在隐式事务中执行,独立于outer
。DoWork1
中没有发生任何事情保证是原子的。如果中途失败,您将获得不一致的数据。此处发生的任何工作始终都会提交,无论outer
发生什么情况。 .inner2
在新事务中执行,独立于outer
。这是与outer
不同的交易但它不嵌套。如果失败,outer
中发生的工作(DoOuterWork()
) 和任何其他范围仍然可以提交,但问题是:如果完成,则回滚整个outer
事务将不会回滚inner2
内完成的工作. 这就是它不是真正嵌套的原因。另外,inner2
将无权访问由outer
锁定的任何行,所以如果你不小心,你可能会在这里陷入僵局。inner3
在与outer
相同的交易中执行。这是默认行为。如果DoWork3()
失败并且inner3
永远不会完成,那么整个outer
事务被回滚。类似地,如果inner3
成功完成但outer
回滚,然后DoWork3()
中完成的任何工作也被回滚。
所以你可以看到这些选项实际上都不是嵌套的,并且不会给你你想要的东西。 Required
选项近似于嵌套事务,但无法让您独立提交或回滚事务内的特定工作单元。
在 SQL Server 中您可以获得的最接近真正嵌套事务的是 SAVE TRAN
结合一些声明TRY/CATCH
block 。如果您可以将逻辑放入一个或多个存储过程中,这将是一个不错的选择。
否则,您需要按照 Oded 的建议对每张发票使用单独的交易。
关于.net - C# 事务中的事务,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2794761/