Страница 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 я, естественно, смотрел,
но, хоть убейте, примера корректной работы с транзакциями
не нашел - все примеры сводятся к

Код: Выделить всё

StartTransaction;
....
Commit;
даже без обработки исключений.
Собственно, меня смутил Ваш пост в 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
прошу ревизию
www.ibase.ru/devinfo/ibx.htm#try

Добавлено: 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
Кузнецов Евгений
kdv писал(а):прошу ревизию
www.ibase.ru/devinfo/ibx.htm#try
Спасибо, все ясно, единственное замечание - на код

Код: Выделить всё

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
Кузнецов Евгений
kdv писал(а):Кстати, при тщательном разборе кода оказалось, что код, который привел Каратаев в этом топике:
http://forum.ibase.ru/phpBB2/viewtopic.php?t=1444
избыточен.
Это код автора топика, просто там цитирование не поставлено.

Добавлено: 09 мар 2007, 20:16
kdv
да, действительно...