Форум: "Основная";
Текущий архив: 2003.09.25;
Скачать: [xml.tar.bz2];
ВнизЕсть ли в DELPHI аналог функции AbnormalTermination()? Найти похожие ветки
← →
mishgan (2003-09-08 10:29) [0]Нужно в блоке try .. finally .. end определить, каким образом произошло выполнение finally-секции: естественным путем, или неявно, например в результате возникновения Exception, либо был вызов exit, break, continue и т.п.
В Visual C++ есть функция AbnormalTermination(). Если вызвать в секции funally, то можно определить как мы в нее попали (явно или неявно).
В DELPHI такой функции не обнаружено (анализ system и sysutils ничего полезного не дал). Поэтому приходится заводить переменные-флажки, а этого не хочется постоянно делать.
← →
mishgan (2003-09-08 15:26) [1]:(((
← →
sts (2003-09-08 19:15) [2]if ExceptObject<>nil then ...
← →
mishgan (2003-09-09 12:28) [3]У меня чей-то ExceptObject всегда nil
procedure TForm1.Button1Click(Sender: TObject);
var
i: real;
begin
i:=0;
try
//raise Exception.Create("raise");
i:=1/i;
finally
if ExceptObject<>nil then
ShowMessage("1:"+FloatToStr(i))
else
ShowMessage("2");
end;
end;
В этом примере всегда выводится "2"
← →
mishgan (2003-09-10 09:50) [4]уп
← →
KSergey (2003-09-10 10:01) [5]Погодите..
Для отлова исключений - есть конструкция try..except (буквального аналога в Си нет, к стати)
В excep секцию попадаем только при возниковени исключения.
Однако же отловить exit, break, continue - здесь не выйдет, это не исключения (к стати, а что за выход по continue??). Но можно вместо этих выходов возбудить исключение и погасить его (в том же try..except). Наверное, это будет то, что надо
← →
mishgan (2003-09-10 10:39) [6]>>Для отлова исключений - есть конструкция try..except
Мне и не нужно их отлавливать. Мне нужно определить как мы попали в finally, нормальным путем или нет (в finally у меня делается Commit/Rollback Transaction). В VC++ это делается в секции finally вызовом функции AbnormalTermination.
>>к стати, а что за выход по continue
Если try .. finally находится в теле цикла, то такое возможно.
>>Но можно вместо этих выходов возбудить исключение
Не, так не интересно. Лучше буду пользоваться флажками, как и сейчас.
← →
KSergey (2003-09-10 10:52) [7][6] mishgan (10.09.03 10:39)
Не, так не интересно. Лучше буду пользоваться флажками, как и сейчас.
Ну и напрасно, по-моему. Впрочем, вам виднее.
По поводу когда делать RollBack.
Я делаю всегда такую конструкцию:
BeginTrans;
try
.. возможно, создание объекта или здесь ничего и нет
try
... какой-то код модификаци БД
CommitTrans; // раз сюда добрались - все прошло успешно
finally
..тут уничтожаем созданный объект(ы)
end;
except
RollBack; // раз сюда попали - случилась невезуха
raise; // в общем случае гасить исключение - не хорошо, пусть об нем все знают
end;
← →
mishgan (2003-09-10 15:02) [8]Если во вложенной секции try .. finally есть exit то транзакция останется незавершенной.
Да и по другим причинам такой вариант не очень катит - транзакция может откатываться не только в случае исключений, а в случае каких-то логических ошибок (которые анализируются отдельно). Получается, что ROLLBACK нужно писать в двух местах - нерасиво:
/////////////
BeginTrans;
try
try
... какой-то код модификаци БД
Errors:=....
finally
if not Errors then
CommitTrans
else
Rollback;
end;
except
RollBack;
raise;
end;
/////////////
Такой код уже не очень красив.
А вот если бы (мечтательно) был AbnormalTermination, то можно было бы обойтись одной секцией try ... finally
← →
clickmaker (2003-09-10 15:11) [9]А такой вариант
try
Errors := false;
BeginTrans;
try
... какой-то код модификаци БД
Errors:=....
if Errors then
Raise Exception.Create("Errors")
finally
if not Errors then Commit;
end;
except
RollBack;
raise;
end;
← →
mishgan (2003-09-10 16:29) [10]clickmaker [9]
Опять же exit (и т.п.) пропустим и останется тогда висеть транзакция надолго (в секцию Except не попадем) :(
← →
clickmaker (2003-09-10 16:33) [11]Ну, в конце концов, можно и так
try
Errors := false;
BeginTrans;
try
... какой-то код модификаци БД
Errors:=....
finally
if not Errors then
Commit
else
Raise Exception.Create("Errors")
end;
except
RollBack;
raise;
end;
← →
vuk (2003-09-10 16:38) [12]Почти то же самое, что у clickmaker только иначе.
Errors := false;
BeginTrans;
try
...
finally
if Errors then
Rollback
else
Commit;
end;
← →
vuk (2003-09-10 16:42) [13]Вместо точек можно написать:
try
DoSomething;
if SomeCondition then
Errors := true;
except
Errors := true;
raise;
end;
← →
mishgan (2003-09-10 17:55) [14]2(12)
Щас почти так и есть:
TrRes := false;
BeginTrans;
try
ErrorCode:=... //insert/update/delete/execute_sp
if ErrorCode<>0 then exit;
...
ErrorCode:=... //insert/update/delete/execute_sp
if ErrorCode<>0 then exit;
...
ErrorCode:=... //insert/update/delete/execute_sp
if ErrorCode<>0 then exit;
...
ErrorCode:=... //insert/update/delete/execute_sp
if ErrorCode<>0 then exit;
...
TrRes:=True; // В finally попадем естественным путем
finally
if (TrRes) and (ErrorCode=0) then
Rollback
else
Commit;
end;
← →
Sandman25 (2003-09-10 18:04) [15]Если есть функция, возвращающая статус незавершенности транзакции, то можно так:
BeginTrans;
try
...
CommitTrans;
finally
if TransActive then
Rollback;
end;
← →
Vuk (2003-09-10 18:29) [16]to mishgan:
У нас в таких случаях, по возможности, пишется одна SP, в которой и делаются все действия и проверки.
← →
KSergey (2003-09-11 07:41) [17][8] mishgan (10.09.03 15:02)
Если во вложенной секции try .. finally есть exit то транзакция останется незавершенной.
Вранье наглое. ;)
Если Exit стоит между try .. finally, но секция finally выполнится по любому!
Да и по другим причинам такой вариант не очень катит - транзакция может откатываться не только в случае исключений, а в случае каких-то логических ошибок (которые анализируются отдельно). Получается, что ROLLBACK нужно писать в двух местах - нерасиво:
Не надо его писать в 2 местах вовсе.
Надо просто в случае проблем генерировать обственное исключение и писать примерно такой код:
type
ERollbackTran = class Exception;
...
BeginTrans;
try
...
if проблема then raise ERollbackTran.Create("..");
...
CommitTran;
except
RollbackTran;
raise;
end;
Можно при необходимости свое исключение обработать по особому. Вот и все. Если по особому обрабатывать не нужно - можно и свой тип не заводить, просто Exception создавать. Да и флаги ни какие не нужны, при любой ошибке - код геренации исключения, можно его в отдельную ф-цию вынести при желании.
И все очень красиво (на мой взгляд).
[11] clickmaker © (10.09.03 16:33)
try
Errors := false;
BeginTrans;
try
... какой-то код модификаци БД
Errors:=....
finally
if not Errors then
Commit
else
Raise Exception.Create("Errors")
end;
except
RollBack;
raise;
end;
А вот так не надо делать (внимание на выделенный фрагмент).
Получится, что если при старте транзакции произойдет исключение - мы тут же вывалимся на RollBack, а ролбэкать-то нечего - транзакция еще не началась. В принципе ничего фатального, драйвер БД не идиот, он проверит при роллбэке была ли начата транзакция и к проблемам код не приведет, однако это не верно.
Так что надо BeginTrans выносить до try..except:
BeginTrans;
try
...
except
RollBack;
raise;
end;
← →
mishgan (2003-09-11 15:13) [18]KSergey [17]
>>Вранье наглое. ;)
>>Если Exit стоит между try .. finally, но секция finally >>выполнится по любому
Это я знаю. Но обрати внимание, что 7-мом посте в finally нет оператора ROLLBACK, он есть в except. В секцию except в случае выполнения Exit мы не попадаем и транзакция остается открытой.
← →
KSergey (2003-09-12 07:03) [19]> [18] mishgan (11.09.03 15:13)
Хм, дейстаивтельно, признаю, в пылу перепалки не все нюансы углядел. ;)
Впрочем, потому и счиатю лучшим рзруливанием - выход с возбуждением исключения.
Страницы: 1 вся ветка
Форум: "Основная";
Текущий архив: 2003.09.25;
Скачать: [xml.tar.bz2];
Память: 0.5 MB
Время: 0.01 c