Страница 1 из 2
IBX - корректная работа с транзакциями
Добавлено: 08 мар 2007, 13:10
Кузнецов Евгений
Доброго времени суток!
Хотя этот вопрос уже поднимался,
остались моменты, которые я не совсем понимаю.
Как правильно работать с транзакциями в IBX?
На сегодняшний момент я делаю так
1)
Код: Выделить всё
StartTransaction
try
<изменения>
Commit;
except
RollBack;
raise;
end;
что в общем, совпадает с кодом, который приводил
Dimitry Sibiryakov в
http://forum.ibase.ru/phpBB2/viewtopic.php?t=1444
Однако в топике
http://forum.ibase.ru/phpBB2/viewtopic.php?t=396
рекомендовался несколько другой подход
2)
Код: Выделить всё
StartTransaction
try
<изменения>
finally
Commit;
end;
если изменения затрагивают одну запись (хотя, в чем разница, не ясно - ведь
если изменение одно и потерпело неудачу, то все равно Rollback
переведет транзакцию в подтвержденное состояние)
или
3)
Код: Выделить всё
StartTransaction
try
<изменения>
except
Rollback;
raise;
end;
Commit;
если несколько.
Если рассматривать общий случай (изменения могут затрагивать несколько
записей) и не учитывать вариант обрыва соединения (который
IBX не может обработать корректно), какой из способов предпочтительнее - 1 или 3?
Т.е. вопрос сводится к тому, в каких случаях Commit навернется,
но соединение с сервером останется? Merlin упоминал о DDL-statements,
но может существуют и другие случаи?
Добавлено: 08 мар 2007, 19:31
kdv
.е. вопрос сводится к тому, в каких случаях Commit навернется,
но соединение с сервером останется? Merlin упоминал о DDL-statements,
но может существуют и другие случаи?
не надо морочить голову себе и людям. в
www.ibase.ru/devinfo/ibx.htm все описано.
Commit если "навернется", то остается сделать Rollback. Если соединение оборвано, то транзакция будет сервером переведена в rollback.
Добавлено: 09 мар 2007, 10:28
Кузнецов Евгений
Доброго времени суток!
To KDV
Спасибо за внесение ясности.
Статью
www.ibase.ru/devinfo/ibx.htm я, естественно, смотрел,
но, хоть убейте, примера корректной работы с транзакциями
не нашел - все примеры сводятся к
даже без обработки исключений.
Собственно, меня смутил Ваш пост в
http://forum.ibase.ru/phpBB2/viewtopic.php?t=1444
от Вт Окт 25, 2005 4:15 pm, где Вы приводите пример кода.
Добавлено: 09 мар 2007, 10:45
kdv
по-моему в том самом топике все разъяснено.
Commit - это применение тех изменений в транзакции, которые "прошли".
Соответственно, это решает разработчик, что делать - Commit или rollback, если какой то из нескольких операторов не прошел.
т.е. я вообще не вижу, где тут "смущаться"
за неясности спасибо, я подумаю, как расширить ibx.htm
Добавлено: 09 мар 2007, 13:19
Кузнецов Евгений
kdv писал(а):Commit - это применение тех изменений в транзакции, которые "прошли".
Соответственно, это решает разработчик, что делать - Commit или rollback, если какой то из нескольких операторов не прошел.
Насколько я представляю, в большинстве случаев делают rollback, иначе зачем тогда транзакция?
kdv писал(а):т.е. я вообще не вижу, где тут "смущаться"

Вот Ваш пример из упомянутого топика:
Код: Выделить всё
StartTransaction
try
<изменения>
except
Rollback;
end;
Commit;
Ну raise в Except здесь не упомянут, но не в этом дело.
Получается, нет особой разницы, где ставить Commit - вне
или внутри секции try-except - все ограничения вроде бы проверяются
при вставке/обновлении записей, а при потере соединения клиентскому
приложению будет уже безразлично, как завершилась транзакция.
Добавлено: 09 мар 2007, 14:53
kdv
Насколько я представляю, в большинстве случаев делают rollback, иначе зачем тогда транзакция?
в большинстве - да. Но тут нет обязаловки или принудиловки - вроде того что если возникла ошибка, то ты ДОЛЖЕН сделать rollback. Не должен.
Получается, нет особой разницы, где ставить Commit - вне
или внутри секции try-except
это как? except обрабатывается при ошибке. commit тут обычно не пишут.
а при потере соединения клиентскому
приложению будет уже безразлично, как завершилась транзакция.
при потере соединения транзакция rollback-ом на сервере откатывается, безусловно.
Добавлено: 09 мар 2007, 14:56
CyberMax
А разве Commit после Rollback не вызовет исключения, что транзакция не активна?
Добавлено: 09 мар 2007, 15:39
kdv
ээээ.... да.
Добавлено: 09 мар 2007, 17:04
CyberMax
kdv писал(а):ээээ.... да.
В смысле вызовет или не вызовет? К сожалению, под рукой нет Дельфи, чтобы проверить.
А по сути вопроса: правильней использовать первый вариант. Commit должен быть в try'e, так как именно его исключения нам надо отловить.
Добавлено: 09 мар 2007, 17:11
WildSery
Вызовет.
Код: Выделить всё
if MyTransaction.inTransaction then MyTransaction.Commit
Добавлено: 09 мар 2007, 17:25
kdv
Добавлено: 09 мар 2007, 17:45
CyberMax
Код: Выделить всё
TW.StartTransaction;
try
Q1.ExecQuery;
Q2.ExecQuery;
...
except
TW.Rollback;
end
if TW.InTransaction then
TW.Commit;
Проведем анализ вышеуказанного кода.
1. В случае возникновения исключения на Q2.ExecQuery, вызовется TW.Rollback, а после - ничего (так как TW.InTransaction = False).
2. В случае отсутствия исключений будет выполнен код TW.Commit.
Теперь перенесем Commit в конец try.
1. В случае возникновения исключения на Q2.ExecQuery, вызовется TW.Rollback, а после - ничего (нет кода).
2. В случае отсутствия исключений будет выполнен код TW.Commit.
Как видим, логика одна и та же, но второй вариант нагляднее и короче (нет проверки активности транзакции). Таким образом, предлагаю правильным вариантом принять:
Код: Выделить всё
TW.StartTransaction;
try
Q1.ExecQuery;
Q2.ExecQuery;
...
TW.Commit;
except
TW.Rollback;
end;
Добавлено: 09 мар 2007, 18:25
Кузнецов Евгений
Спасибо, все ясно, единственное замечание - на код
Код: Выделить всё
TW.StartTransaction;
try
try
Q1.ExecQuery;
except
TW.Rollback;
Result:=False; // говорит о том что произошла ошибка
end;
finally
if TW.InTransaction then
begin
TW.Commit;
Result:=True // ошибок нет
end;
end;
Delphi будет ругаться: Return value of function might be undefined,
так что Result:=False лучше перенести в самое начало.
Остается проблема потери коннекта - как я понимаю, IBX в этом
случае впадает в ступор и упомянутый код вывалится с исключением.
Правда, есть пара патчей у Вас на сайте и версия 6.084 от О. Пащенко - надо будет попробовать.
Добавлено: 09 мар 2007, 19:00
EvilsInterrupt
так что Result:=False
зы:
По окончании реализации смотрят чего больше возвращает ф-ция, и следовательно именно это "больше" присваивают в самом начале!

Добавлено: 09 мар 2007, 19:05
kdv
По окончании реализации смотрят чего больше возвращает ф-ция, и следовательно именно это "больше" присваивают в самом начале!
не так. подход должен быть пессимистический. сначала мы предполагаем, что все рухнет к чертовой матери. А дальше пишем, и по мере успешного исполнения двигаемся к позитиву.
Добавлено: 09 мар 2007, 19:15
EvilsInterrupt
kdv
В плане отладки твой метод помогает! Но! Когда надо написать ф-цию которая будет вызываться очень часть и которую надо оптимизировать по эффективности выполнения кода. Излишние присваивания никчему!
Добавлено: 09 мар 2007, 19:23
kdv
надо оптимизировать по эффективности выполнения кода. Излишние присваивания никчему!
бог ты мой. result:=False в начале, и :=True когда все выполнилось. Где тут лишние присваивания?
Кстати, при тщательном разборе кода оказалось, что код, который привел Каратаев в этом топике:
http://forum.ibase.ru/phpBB2/viewtopic.php?t=1444
избыточен.
Код: Выделить всё
Start
try
try
Exec
except
rollback
end
finally
commit
end
? Зачем тут два блока try, если правильно группируются Exec и Commit, причем работать это будет в любой ситуации.
Добавлено: 09 мар 2007, 19:46
hvlad
EvilsInterrupt писал(а):Когда надо написать ф-цию которая будет вызываться очень часть и которую надо оптимизировать по эффективности выполнения кода. Излишние присваивания никчему!
Это работа компилятора.
Добавлено: 09 мар 2007, 19:54
Кузнецов Евгений
Это код автора топика, просто там цитирование не поставлено.
Добавлено: 09 мар 2007, 20:16
kdv
да, действительно...