Обработка исключений при добавлении данных в БД (Delphi)

IBX, FIBPlus, UIB, ADO, .Net и прочее-прочее-прочее, в общем все, что относится к созданию приложений, работающих с InterBase, Firebird и Yaffil - клиент-серверных, трехзвенных, консольных и т.п.

Модератор: kdv

Ответить
maker
Сообщения: 3
Зарегистрирован: 06 фев 2005, 12:47

Обработка исключений при добавлении данных в БД (Delphi)

Сообщение maker » 06 фев 2005, 13:08

как будет правильней

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

towns_write.StartTransaction;

DS_towns.append;
 <..........>
 try   DS_towns.Post;
 except   DS_towns.Cancel;
 end;

 try   towns_write.Commit;
 except   towns_write.Rollback;
 end

или может второй блок try вставить сразу после post'a
или может ни то ни другое неправильно...
[/code]

Merlin
Динозавр IB/FB
Сообщения: 1502
Зарегистрирован: 27 окт 2004, 11:44

Re: Обработка исключений при добавлении данных в БД (Delphi)

Сообщение Merlin » 06 фев 2005, 15:25

maker писал(а):как будет правильней

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

towns_write.StartTransaction;

DS_towns.append;
 <..........>
 try   DS_towns.Post;
 except   DS_towns.Cancel;
 end;

 try   towns_write.Commit;
 except   towns_write.Rollback;
 end

или может второй блок try вставить сразу после post'a
или может ни то ни другое неправильно...
[/code]
Зависит от того, что ещё происходит между starttransaction и именно этим post. В смысле делаются ли ещё изменения в базе кроме этого post и если делаются, то следует ли их сохранять без этого изменения. А ещё от того, требуется ли вообще коммитить изменения каждой записи или можно пачкой. Post посылает изменения записи на сервер, что приводит к появлению новой версии записи, которую по чтению пока никто не видит, но которая блокирует попытки изменения этой записи другими транзакциями, если они read_commited до нашего коммита, если concurrency до их рестарта. По коммиту все _выполненные_ в рамках транзакции изменения становятся актуальными. Именно выполненные, а _не выполненные_ не становятся. Независимо от того, не делали их вообще или они обломились. То есть, в сценарии

starttransaction
update record1 - successffull
update record2 - failed
update record3 - successffull
commit

на сервере будут благополучно выполнены и актуализированы изменения записей 1 и 3. А в сценарии

starttransaction
record2 - failed
commit

на сервере ничего не записано и не актуализировано. Причём завершать такую транзакцию лучше именно по коммит для облегчения жизни серверу, почему - рассказывать долго. Роллбак нужен только в сценарии типа первого если нельзя актуализировать изменения записей 1 и 3 без изменений записи 2.

Кстати, насколько я понимаю в колбасных обрезках, коммит может дать exception только в двух случаях:
- если внутри транзакции выполняются операторы DDL;
- при потере коннекта с сервером.

Ну вот, я тебя запутал окончательно, теперь сам думай, чего тебе надобно, старче :)

maker
Сообщения: 3
Зарегистрирован: 06 фев 2005, 12:47

Сообщение maker » 06 фев 2005, 20:56

вообще в данном случае добавляется только одна запись, т.е. между append и post заполняются поля одной записи. И просто хотелось бы узнать, как правильней обработать ошибки, если что-то не так.

kdv
Forum Admin
Сообщения: 6595
Зарегистрирован: 25 окт 2004, 18:07

Сообщение kdv » 07 фев 2005, 09:32

Merlin, заносит тебя иногда... :wink:

я вот тоже на текст особо не смотрел, а пригляделся - ну и ну.

если все это написано именно так как выглядит, то работать не будет, потому что:

1. первый exception будет съеден первым except. Поэтому всегда будет вызываться commit.

2. DS_towns.Cancel не "отменяет" ввод записи. См. хелп. То есть, конечно, отменяет, но на уровне "ввода клиента". То есть, таким способом рубить клиенту ввод новой записи - извините. По любой ошибке тут же сразу хрясь - и DataSet в предыдущий вид возвращать?

3. Как сказал Merlin, commit может выдать ошибку только если сервер сдох или соединение оборвано (еще на savepoints). То есть, когда уже собственно, поздно делать commit.

Так что, я бы написал (если добавление записи автоматизировано, а так конечно если это интерактивный ввод пользователя, то так не пишут)

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

towns_write.StartTransaction;
try
  DS_towns.append;
  <..........>
  DS_towns.Post;
except  
  on ...
        DS_towns.Cancel;
end;
towns_write.Commit;
Если там, где post, больше чем один оператор выполняется, тогда конечно так

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

towns_write.StartTransaction;
try
  DS_towns.append;
  <..........>
  DS_towns.Post;
  towns_write.Commit;
except  
  on ...
      begin
        DS_towns.Cancel;
         ...
        towns_write.Rollback;
end;
извините за мой французский, если что. :wink: :wink: :)

Merlin
Динозавр IB/FB
Сообщения: 1502
Зарегистрирован: 27 окт 2004, 11:44

Сообщение Merlin » 07 фев 2005, 12:35

kdv писал(а):Merlin, заносит тебя иногда... :wink:
Дык потому всё больше и прикалываюсь. Или под настроение разжёвываю какой-нибудь абсолютный примитив, раскрывая вокруг него горизонты, типа думать учу :) А как пытаюсь всерьёз что-то на среднем уровне изложить, так и несёт - втиснуть всего Дейта с Грабером в одну ёмкую толстовскую фразу :)
kdv писал(а):
если все это написано именно так как выглядит, то работать не будет, потому что:

1. первый exception будет съеден первым except. Поэтому всегда будет вызываться commit.
Если это update одной записи, то почему же не будет-то? Как раз и будет, причём без лишних роллбаков. Что получилось - закоммитит, что нет - отпустит транзакцию.
kdv писал(а): 2. DS_towns.Cancel не "отменяет" ввод записи. См. хелп. То есть, конечно, отменяет, но на уровне "ввода клиента". То есть, таким способом рубить клиенту ввод новой записи - извините. По любой ошибке тут же сразу хрясь - и DataSet в предыдущий вид возвращать?
Топорно конечно, но это дело его личного вкуса. Когда захочет - научится и конфликт обрабатывать и при настоящих неприятностях показывать причину и всё не теряя буфера ввода. Правда на одном гриде этого в общем случае не сделаешь, тут малость поболе потрудиться надо. Но это меня уже опять понесло ;)
kdv писал(а): 3. Как сказал Merlin, commit может выдать ошибку только если сервер сдох или соединение оборвано (еще на savepoints). То есть, когда уже собственно, поздно делать commit.
И ещё при выполнении DDL, где основную работу сервер делает именно на коммите, а при выполнении операторов, грубо говоря, берёт для этого данные себе на заметку. Хотя ему об этом рано пожалуй :) isql по умолчанию работает в autocommit DDL, по-моему Хвастунов и др. в конце концов тоже к этому пришли. А "Как сказал Merlin" - это звучит :lol:
kdv писал(а): Так что, я бы написал (если добавление записи автоматизировано, а так конечно если это интерактивный ввод пользователя, то так не пишут)

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

towns_write.StartTransaction;
try
  DS_towns.append;
  <..........>
  DS_towns.Post;
except  
  on ...
        DS_towns.Cancel;
end;
towns_write.Commit;


Если приглядеться к его коду, то он отработает также, за исключением того, что если при коммите шнурок таки оборван, то выдаст ещё и исключение на роллбаке :) Но в этом случае уже вообще всё по фигу, IBX при обрыве уходит в штопор, как известно, навсегда.

Ответить