У меня есть некоторый код для обновления таблицы базы данных, которая похожа
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
}
но как я записал бы деструктор для него?
Используйте следующее:
transaction tr(db);
...
tr.commit();
Когда tr.commit ()
завершается, он устанавливает состояние "фиксация выполнена", а деструктор ничего не делает, {{1} } иначе происходит откат.
Проверка на исключение - плохая идея, примите во внимание:
transaction tr(db);
...
if(something_wrong)
return; // Not throw
...
tr.commit();
В этом случае вы, вероятно, ожидаете скорее отката , а затем фиксации, но фиксация будет выполнена.
Изменить: , но если вы все еще сильно этого хотите, посмотрите std :: uncaught_exception ()
, но прочтите сначала http: // www .gotw.ca / gotw / 047.htm
Самый простой способ, который я могу придумать, - это установить частную переменную-член в классе в исключении и протестировать ее / выполнить соответствующее действие в деструкторе .
Вы можете использовать следующую логику:
Удаляя обработку исключений, вы нарушаете свой 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"
}
Различия с исходным кодом - вот что побудило мой ответ:
В «ловушке» ничего не требуется: деструктор предполагает автоматический откат, если не был вызван метод commit () с успехом (, который может, например, установить для некоторого частного логического члена DBTransaction значение true ). Уловка заключается в том, что код будет продолжаться, если транзакция не удалась.
Вы должны создать специальное исключение (я назвал его DBTransactionRollback), чтобы генерировать момент сбоя в одной из ваших команд. Таким образом, функция catch будет улавливать только исключение, вызванное откатом транзакции, но не другие исключения (например, STL и т. Д.)
. Использование механизма исключения позволяет вам поместить свой код в несколько функций, вызываемых из этого блока try / catch. кода, без необходимости иметь дело с логическими возвратами и другими возвратами кода ошибки.
Надеюсь, это ответит на ваш вопрос.