|
|
|
/ASA/ Transact SQL ХП: правильно обработать ошибку и откатиться?
|
|||
|---|---|---|---|
|
#18+
И опять про обработку ошибок в хранимых процедурах :).\r \r Поискал по форуму\r А как же транзакции???\r Как обеспечить атомарность изменений в ХП???\r Транзакции в хранимых процедурах\r \r Прочитал статейку Implementing Error Handling with Stored Procedures \r \r Хочется получить способ написания хранимых процедур в ASA9, в результате применения которого получаются процедуры, которые:\r 1. При ошибке откадываются до точки входа в процедуру или откатывают открытую транзакцию.\r 2. Произошедшая ошибка возвращается клиенту в исходном виде. То есть как если в "цивилизованном" языке сделать try .. except rollback raise end.\r 3. Текcт процедуры совместим с как можно бОльшим количеством других серверов, что означает\r 4. нужно использовать только Transact-SQL.\r \r Начал с BOL, плавно переходящий в google, что закончилось прочтением статьи Using transactions in stored procedures and triggers с сайта Sybase.\r \r В статье все очень хорошо описано. Из нее, в частности, следует что все вместе получить не удастся, что расстроило меня окончательно. А не удастся потому что другая статья с Sybase гласит, что\r \r Если процедура на Transact-SQL, то все зависит от опции ON_TSQL_ERROR :\r \'STOP\' : ошибка летит на клиента, но тогда ничего не откатывается. Конечно, начатую в процедуре транзакцию можно откатывать на клиенте, но как-то коряво получается. Учили же - где ты объект создашь, там ты за собой и убери. Можно еще не начинать транзакцию в процедуре, а все делать с клиента, но это тоже как-то подозрительно.\r \'CONTINUE\' : ошибку можно обработать, проверяя @@error, SQLSTATE и SQLCODE и делать все что душе угодно. Не дает покоя одна вещь - к моменту завершения строчки "SELECT @Error = @@error" ошибки уже не существует.\r \r То есть, если каждую строчку обрамлять в IF, то откатить все можно замечательно, но вот про возвращение исходной ошибки придется забыть.\r \r Также выяснил что SQLSTATE и SQLCODE - вещи очень хорошие, и если вовремя их запомнить то впоследствии можно получить текст сообщения для исходной ошибки. @@error в этом отношении убога - имеет пару десятков значений, и в большинстве случаев это -16 \'Other User Error\'. Очень содержательно :).\r \r Значит, код ошибки и сообщение получили. Как же их теперь на клинта запулить? Первом делом взгляд падает на RaisError, но оказывается что ей можно пулять только "пользовательские" ошибки, и при попытке запулить ошибку с кодом из SQLCODE на клиенте получаем "Error number for RaisError may not be less than 17000" :(.\r \r Вы спросите, зачем мне так нужен код ошибки? На клиенте хочется обрабатывать ошибки "в одном месте" :) и в зависимости от кода ошибки подгружать дополнительное объяснение для пользователя что произошло. Да и уютнее как-то когда ты ошибку не прячешь, а передаешь дальше по цепочке.\r \r Замечательную идею излагают в обсуждении Хороший тон в процедурах. Использовать триггер для выбрасывания ошибки, тем самым откатывая транзакцию. Только опять мы у разбитого корыта - тот же RaisError.\r \r Хорошо иметь на MSSQL опцию SET XACT_ABORT ON (которая, как я понял, тоже не для всего работает). Хорошо писать на watcom и иметь except и resignal (как я понял из описания, resignal работает как raise?).\r \r Но как же быть с ASA и Transact SQL?\r \r В общем, на пока решили возвращать SQLCODE как доп. параметр с условленным именем из каждой процедуры, и на клиенте обрабатывать в общем месте. При помощи доп. кода подогнать так, что ошибка "вручнцю" будет эквивалентна серверной ошибке. Ну и, соответственно, все хранимые процедуры "подкручивать" чтобы после вызова вложенной процедуры они бы проверяли не только SQLCODE, но и те самые условленные параметры.\r \r Но неужели нельзя чтобы и просто и работало как следует?\r \r Спасибо. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 07.02.2004, 07:28 |
|
||
|
/ASA/ Transact SQL ХП: правильно обработать ошибку и откатиться?
|
|||
|---|---|---|---|
|
#18+
Такая модель обработки ошибок в TSQL поддерживается в ASA из за совместимости с ASE (впрочем как и все урезки TSQL). По красивому не получится. авторКонечно, начатую в процедуре транзакцию можно откатывать на клиенте, но как-то коряво получается. Учили же - где ты объект создашь, там ты за собой и убери. Можно еще не начинать транзакцию в процедуре, а все делать с клиента, но это тоже как-то подозрительно. Все зависит от того, что Вы делаете. Например в PowerBuilder считается хорошим тоном при сохранении изменений в данных через Embedded SQL (SQL встроен прямо в язык) стартовать транзакцию, записывать изменения наборов данных (в том числе и через ХП) и сохранять или откатывать транзакцию в зависимости от успешности выполнения. С другой стороны, если ХП вызывается для проведения каких то операций и сама отвечает за атомарность всех изменений данных, то конечно же клиент к транзакциям никакого отношения иметь не должен. авторВ общем, на пока решили возвращать SQLCODE как доп. параметр с условленным именем из каждой процедуры, и на клиенте обрабатывать в общем месте. Попробуйте вот так: Код: plaintext 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 20. Опция обеспечивает, что выполнение будет продолжено после возникновения системной ошибки. Так что спокойно можно откатить транзакцию и выйти. Код ошибки будет по любому возвращен клиенту после выхода из ХП. Для обработки пользовательских ошибок можно работать вот так: Код: plaintext 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 20. 21. 22. 23. 24. Пользовательская ошибка будет с случае возникновения обработана, транзакция откатана, а клиентскому приложению вернется: RAISERROR выполнен: В этот день работать не стоит ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 07.02.2004, 18:36 |
|
||
|
/ASA/ Transact SQL ХП: правильно обработать ошибку и откатиться?
|
|||
|---|---|---|---|
|
#18+
Дело в том, что в случае обработки ошибки в процедуре на клиента она уже не возвращается. По крайней мере не в первозданном виде, это точно. Пробовал создать 3 разных "ошибочных" процедуры и запустить их прямо из isql. Опция Stop ON_TSQL_ERROR = 'CONDITIONAL'. Все три делали return @error (которая набивалась из @@error). Первая после ошибки ничего не делала, в результате чего возвращалось красивое сообщение со всеми кодами ошибок. Транзакция, понятное дело, не откатывалась. Во второй обрабатывал ошибку, откатывая транзвкцию. В результате ошибка терялась и никаких сообщений не выскакивало. Третья после отката делала RAISERROR. Получаемое сообщение имело уже мой код ошибки и мое сообщение. Я описал как можно сохранить информацию об ошибке, но при этом уж слишком много ручной работы получается. Причем это после каждого вызова надо обходить вокруг и стучать по колесам :). А транзакции - да, хотелось бы чтобы большинство процедур были атомарными. "Создать заказ", "Оплатить счет", и т.д. Их таким образом можно и из открытой транзакции вызывать (где их транзакционность уже не сильно важна), так и индивидуально для одиночных операций. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 11.02.2004, 05:41 |
|
||
|
|

start [/forum/topic.php?fid=55&msg=32404937&tid=2014667]: |
0ms |
get settings: |
10ms |
get forum list: |
13ms |
check forum access: |
4ms |
check topic access: |
4ms |
track hit: |
162ms |
get topic data: |
12ms |
get forum data: |
3ms |
get page messages: |
48ms |
get tp. blocked users: |
2ms |
| others: | 229ms |
| total: | 487ms |

| 0 / 0 |

Извините, этот баннер — требование Роскомнадзора для исполнения 152 ФЗ.
«На сайте осуществляется обработка файлов cookie, необходимых для работы сайта, а также для анализа использования сайта и улучшения предоставляемых сервисов с использованием метрической программы Яндекс.Метрика. Продолжая использовать сайт, вы даёте согласие с использованием данных технологий».
... ля, ля, ля ...