我现在已经看过几次了这个模式:
bool success = false;
try
{
DoSomething();
success = true;
}
finally
{
if (!success)
Rollback();
}
我一直在想:为什么这比使用catch进行回滚更好?
try
{
DoSomething();
}
catch
{
Rollback();
throw;
}
确保更改在失败时回滚的两种方法之间有什么区别?
答案 0 :(得分:4)
我在这里发布了一些代码,即使它与问题没有关系(稍后会删除)。
通过这个程序:
using System;
namespace testcs
{
class Program
{
static void Main(string[] args)
{
try
{
try
{
foo();
foo();
foo();
}
catch
{
throw;
}
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
}
private static void foo()
{
throw new Exception("oops");
}
}
}
保留堆栈跟踪(查看行号!),但在main
函数内,您将看到"第19行",throw
所在的行已调用foo()
的 true 行(第13行)。
答案 1 :(得分:2)
finally
语句通常用于清理资源。如果异常不是回滚事务的唯一原因,那么Rollback()
方法可能可以在那里使用。 Close()
或Dispose()
方法是最终块中的主要候选者。
但是,您不希望在那里执行任何可以抛出异常的内容。
答案 2 :(得分:2)
我不确定这不仅仅是anecdotal evidence,但我个人使用这种模式是出于一个非常实际的原因:当DoSomething
抛出异常时,Visual Studio调试器将会进入{ {1}}在第一个版本中发生异常,而在第二个版本中它将在DoSomething
处中断。这允许在throw;
清除所有内容之前检查应用程序状态。
答案 3 :(得分:2)
如果你不关心这个特定的代码,你会使用什么类型的异常:
try
{
DoSomething();
ok = true;
}
finally
{
if(!ok)Rollback();
}
这将以原始形式保留调用堆栈100%。 此外,如果您使用这样的异常处理:
try
{
DoSomething();
ok = true;
}
catch(FirstExcetionType e1)
{
//do something
}
catch(SecondExcetionType e2)
{
//do something
}
catch(Exception e3)
{
//do something
}
finally
{
if(!ok)Rollback();
}
最后使用finally可以使您的代码比从每个catch语句调用回滚更具可读性。
答案 4 :(得分:1)
finally
,而不仅仅是捕获异常。
当然,在这种特定情况下,只有在出现错误时才需要回滚,但作为一般模式,try-finally
可能对资源管理更有用(通常您需要确保始终{正确地{1}}或Close()
您的资源。特别是如果代码的作者来自Java背景,这个成语更广泛。
答案 5 :(得分:0)
这里明确的目标是在发生任何错误时调用Rollback
。两个代码片段都实现了这一目标。第一个使用始终运行的finally,验证成功到达try
块的最后一行。第二个捕获任何错误,回滚事务,然后重新抛出捕获的异常。任何一个片段的结果都是抛出的任何异常都会导致回滚,同时仍然冒泡到下一个级别。
您提到该项目是从Java移植的。在Java中,您可以 re-throw an exception类似于使用throw;
在C#中的方式。您还可以throw a new exception继续维护调用堆栈(等)。第二个在C#中更清晰/更简单(虽然不是很多),第一个具有实际使用Java编写的优势。