我有以下代码
try {
//Some code here that could throw an exception
} catch (Exception e) {
//handleExc contains code to Update the database
handleExc();
}
如果抛出异常,我正在尝试更新数据库。 但我的问题是更新catch块内的数据库也可能引发异常。
handleExc()方法包含在引发意外异常时更新数据库中的行的代码。 我确保它一直有效。
但是,现在我开始思考,
我知道可以在catch块中抛出异常的语句的异常不会被捕获吗?
是否有一种我不知道的优雅方式,可以在这种情况下使用?
PS。我正在使用C#和asp.net以及sqlserver,但我猜我的问题可以推广到任何编程语言
答案 0 :(得分:0)
这就是数据库(包括MS SQL Server)支持事务的原因。
您正在尝试重新发明交易,但是从客户端执行。您正在讨论的部分是“回滚”阶段。数据库实现了这一点,因为在客户端代码中没有真正的方法可以实现它并确保其正常工作。
使用真实事务,您可以指定一系列所有需要以原子方式一起执行的操作 - 数据库服务器确保所有事情都发生(就好像它们都是一次完成的)或者没有他们发生了。
基本思想看起来像这样:
begin transaction
change A
change B
change C
commit transaction
如果在(比方说)更改C期间出现问题,则事务将永远不会被提交,之后数据库将处于相同的状态,就像更改A和更改B从未发生过一样。
基本上,你在客户端试图破解的任何东西最终都会遇到问题 - 或者更确切地说,主要是一个问题:无论try
/ catch
多少级别阻止你尝试嵌套,你总是有可能做了以后需要撤消的事情,如果你失去了与服务器的连接,你就不能再撤消了。更糟糕的是,即使没有出现任何问题,您也可能最终导致数据库暂时不一致,例如说某些库存已经消失而没有收到付款(反之亦然)。
设计良好的数据库通常使用事务日志来实现事务。这意味着它首先记录交易所需的内容。然后它开始执行事务指定的更改。如果(例如)数据库服务器在事务中间断电,当它开始备份时,它可以将数据库回滚到最后一个部分事务开始之前的状态,然后它可以重放事务日志从那里前进。
我会再说一遍:客户端无法做的就是为您的数据提供这种级别的保护。
那就是说,让我们考虑在一些不涉及数据库的其他情况下你需要做些什么。您需要做的主要事情是决定您真正希望做什么。如果您已经完成了以后需要撤消的操作,但撤消步骤可能会抛出异常,那么您将决定要执行的操作。
大多数语言都允许您在try
内嵌入catch
:
try {
make change A
}
catch (foo) {
try {
undo change A
}
catch (bar) {
// what to do now?
}
}
很有可能在catch (bar)
块内你可以做的就是警告你的用户事情已经发生了可怕的错误,然后记录错误以通知你需要修复的东西。如果它是(例如)与服务器的不可连接的连接,那么可能想等待一点点并重试。