我有一些代码来更新看起来像
的数据库表try
{
db.execute("BEGIN");
// Lots of DELETE and INSERT
db.execute("COMMIT");
}
catch (DBException&)
{
db.execute("ROLLBACK");
}
我想将事务逻辑包装在RAII类中,以便我可以编写
{
DBTransaction trans(db);
// Lots of DELETE and INSERT
}
但我该如何为它编写析构函数?
答案 0 :(得分:12)
使用以下内容:
transaction tr(db);
...
tr.commit();
当tr.commit()
完成时,它将状态设置为“commit done”,析构函数不执行任何操作,
否则它会回滚。
检查异常是个坏主意,请考虑:
transaction tr(db);
...
if(something_wrong)
return; // Not throw
...
tr.commit();
在这种情况下,您可能希望 rollback 然后提交,但提交将完成。
修改,但如果您仍然想要它,请先查看std::uncaught_exception()
但先阅读 http://www.gotw.ca/gotw/047.htm
答案 1 :(得分:3)
您可以使用以下逻辑:
答案 2 :(得分:2)
通过删除异常处理,您正在削弱RAII。
代码应为
try
{
DBTransaction trans(db) ;
// Lots of DELETE and INSERT
// should one fail, a DBTransactionRollback exception will be thrown
trans.commit() ;
}
catch(const DBTransactionRollback & e)
{
// If really needed, you could extract failure information from "e"
}
与原始代码的不同之处在于我的回答:
“catch”中没有任何内容:析构函数将假定自动回滚,除非成功调用了commit()方法(例如,可以设置DBTransaction的一些私有布尔成员真的)。假设交易失败,捕获是代码将继续的位置。
您应该创建一个专用异常(我将其命名为DBTransactionRollback),以便在您的某个命令中丢失某些内容。因此,catch只会捕获事务回滚驱动的异常,而不是其他异常(如STL等)
使用异常机制可以将代码放在多个函数中,从这个try / catch代码块调用,而不必处理布尔返回和其他错误代码返回。
< / LI> 醇>希望这能回答你的问题。
答案 3 :(得分:1)
我能想到的最简单的方法是在异常中的类中设置一个私有成员变量,并在析构函数中测试它/执行适当的操作。