Обробка помилок

Всі повноцінні мови програмування пропонують який-небудь метод перехоплення, протоколювання та обробки помилок У цьому відношенні мови Т-SQL було нічим похвалитися, проте тепер прогрес у наявності У Загалом обробка помилок працює добре (за винятком кількох зауважень), але існує кілька фатальних помилок, які призводять до припинення виконання коду, що не надаючи вам ніякої можливості їх тестування і обробки

Команда Try Catch привнесла в SQL Server засоби обробки помилок Новинка *** століття Після переведення своїх баз даних в середу SQL Server 2005 в першому

2005 Gчергу перебудуйте обробку помилок

Try..Catch

Вираз Try Catch є стандартним методом перехоплення і обробки помилок, який програмісти використовують вже довгі роки Основна ідея полягає в тому, що виконується спроба виконати фрагмент програми, і якщо при цьому виникають які-або помилки, то вони обробляються в секції Catch Загальна структура вираження така:

BEGIN TRY

<Програма>

END TRY BEGIN CATCH

<Програма>

END CATCH

Компілятор T-SQL трактує комбінацію try Begin catch як єдину команду Як і в будь-який інший інструкції, наявність термінатора до або крапки з комою між цими двома командами призведе до необроблюваної помилку Інструкція begin catch повинна слідувати безпосередньо за end try

Якщо при виконанні секції try відбувається яка-небудь помилка, то управління негайно віддається секції catch Якщо секція try виконується без помилок, то блок catch взагалі не виконується Наведемо приклад:

BEGIN TRY

SELECT 1 Перша спроба ;

RAISERROR(1 Імітація помилки1, 16, 1)

Select Друга спроба;

END TRY BEGIN CATCH

SELECT Секція обробки помилки;

END CATCH

SELECT Третя спроба 1

Буде отримано наступний результат:

Перша спроба

Секція обробки помилок

Третя спроба (1 row (s) affected)

У цьому прикладі SQL Server виконує секцію try, поки не зустрічає функцію raise г г or, що імітує помилку Після цього управління передається в секцію catch Слідом за блоком catch виконується наступна по порядку інструкція, що виводить повідомлення про третій спробі

Якщо в блоці try відбувається помилка і управління передається в секцію catch, туди ж потрапляє і інформація про помилку Цю інформацію можна витягти за допомогою функцій, перерахованих в табл 182 Ці функції були спеціально створені для секції catch – поза цього блоку вони завжди повертають пусте значення null

Таблиця 182 Функції перехоплення

Функція

Що повертає

&nbsp

Error_Message()

Текст повідомлення про помилку

&nbsp

Error_Number()

Номер помилки

&nbsp

Функція

Що повертає

Error Procedure()

Імя збереженої процедури або тригера, в яких виникла помилка

Error_Severity()

Небезпека помилки

Error_State()

Стан помилки

Функції перехоплення витягують інформацію про помилку, що викликала перехід до блоку catch Вони можуть викликатися безліч разів, але все одно зберігають інформацію про помилку У блоці catch наступна інструкція SELECT може витягти повну інформацію про помилку: SELECT

ERROR_MESSAGE() AS [Message],

ERROR_PROCEDURE() AS [Procedure],

ERROR_LINE() AS Line,

ERROR_NUMBER() AS Number,

ERROR_SEVERITY() AS Severity,

ERROR_STATE() AS State

Результат виконання інструкції:

Message            Procedure Line Number Severity State

Імітація помилки NULL 4 50000 16 січня

Отримані дані можуть згодом бути запротокольовані в журналі помилок

Стара глобальна змінна @ @ Еггог

Історично склалося так, що обробка помилок в Т-SQL завжди кульгала на обидві ноги Основна інформація зберігалася в глобальних змінних @ @ Еггог і @ @ rowcount Вона містила стан виконання попередньої інструкції нульове значення відповідало відсутності помилок

Складність полягала в тому, що, на відміну від інших мов, інформація про останню помилково не зберігалася до тих пір, поки не зявлялася наступна Значення змінної @ @ Еггог оновлювалося після виконання кожній інструкції, навіть після операції тестування її значення

У наступному прикладі ми спробуємо оновити значення первинного ключа на вже існуюче При цьому будуть порушені обмеження зовнішнього ключа і буде згенерована помилка Дві команди print демонструють, що значення змінної @ @ Еггог змінюється з кожною інструкцією Перша команда print відображає інформацію про успіх чи помилку оновлення друга команда print відображає успіх чи помилку виконання першій:

USE Family

UPDATE Person

SET PersonID = 1 Where PersonID = 2

Print @@Error

Print @@Error

Результат виконання пакету:

Server: Msg 547, Level 16, State 1, Line 1

UPDATE statement conflicted with COLUMN REFERENCE constraint

‘FK_______ Marriage___ Husband   7B905C75. The conflict occurred in

database Family, table Marriage, column HusbandID.

The statement has been terminated

547

0

Рішення проблеми збереження значення останньої помилки полягає у використанні локальної змінної Цей метод дозволяє зберегти статус помилки доти, поки вона не буде правильно оброблена У наступному прикладі такої змінної є @ егг:

USE Family

DECLARE @err INT

UPDATE Person

SET PersonID = 1 Where PersonID = 2 SET @err = @@Error

IF @err &lt&gt 0 Begin

– Код обробки помилки

Print @err

End

У результаті на друк буде виведено наступне повідомлення:

Msg 547, Level 16, State 1, Line 1

UPDATE statement conflicted with COLUMN REFERENCE constraint

‘ FK_____ Marriage__ Husban          7B905C75. The conflict occurred in database

‘Family1, table Marriage1, column HusbandID.

The statement has been terminated

547

Глобальна змінна @ @ RowCount

Після перевірки успіху виконання запиту потрібно знайти кількість виконаних рядків програми, щоб локалізувати помилку Навіть якщо помилку не була згенерована, все одно існує ймовірність того, що дані не відповідають і операція не була виконана Глобальна змінна @ @ RowCount дозволяє перевірити ефективність запиту

Питання оновлення значень, характерні для змінної @ @ Еггог, не оминають і змінну @ @ RowCount У той же час немає ніякого сенсу зберігати нульове значення

У наступному пакеті мінлива @ @ RowCount використовується для перевірки числа оновлених рядків Відсутність результату штучно викликається некоректним умовою пропозиції WHERE У таблиці не існує особистості з ідентифікатором 100, а змінна @ @ RowCount використовується для локалізації причини помилки:

USE FAMILY

UPDATE Person

SET LastName = Johnson

WHERE PersonID = 100

IF @@RowCount = 0 Begin

– Код обробки помилки

Print He оброблено жодного рядка

End

Результат виконання пакету буде наступним:

Чи не оброблено жодного рядка

Raiserror

Щоб повернути довільне повідомлення про помилку в зухвалу процедуру або клієнтський додаток, використовують команду raiserror Існують дві форми цієї команди: стара спрощена і рекомендована повна

Проста форма команди Raiserror

Проста форма команди Raiserror, існуюча з часів Sybase, передає тільки номер помилки і повідомлення Рівень небезпеки завжди встановлюється в 16 – визначається користувачем:

RAISERROR нсмер_ошібкі, повідомлення

Наприклад, наступний програмний код повертає просте повідомлення про помилку: RAISERROR 5551212 Неможливо оновити клієнта

Результат виконання команди:

Msg 5551212, Level 16, State 1, Line 1 Неможливо оновити клієнта

Повна форма команди Raiserror

Удосконалена форма команди Raiserror увібрала в себе чотири нові функції

■ Вказує рівень небезпеки помилки

■ Дозволяє динамічно змінювати повідомлення

У Використовує збережені повідомлення рівня сервера

■ Дозволяє протоколювати помилки в журнал

Синтаксис цієї команди для Windows наступний

RAISERROR (повідомлення або номер, небезпека, стан, дополнітельние_аргументи) With Log

Небезпека помилки

В системі Windows встановлена ​​система стандартних кодів небезпеки помилок (табл 183) Коди, не перераховані в таблиці, зарезервовані компанією Microsoft

Таблиця 183 Доступні коди небезпеки

Код небезпеки

Опис

10

Помилку не сгенерирована, але повертається повідомлення, наприклад за допомогою коман-ди print

11-13

Ні спеціального значення

14

Інформаційне повідомлення

15

Попередження: щось пішло не так

16

Критична помилка Виконання процедури припинено

Додавання в повідомлення змінних параметрів

Повідомлення про помилку може містити фіксовану рядок або номер помилки Для кожного з цих типів існують додаткові аргументи, які підставляються на фіксовані місця в повідомленні Доступні різні їх типи, але мені здаються самими корисними% s – для рядка і% i – для знакового цілого числа Наведу приклад, який використовує один строковий аргумент:

RAISERROR (Неможливо оновити% s’, 14, 1, Customer)

Буде отримано наступний результат:

Msg 50000, Level 14, State 1, Line 1 Неможливо оновити Customer

Збережені повідомлення

Команда raiserror системи Windows також може витягти повідомлення з системного уявлення sysmessages Номери повідомлень 1-50000 зарезервовані компанією Microsoft, а більш високі доступні для користувачів Основною перевагою використання збережених повідомлень є їх послідовність і пронумеровані

Слід зауважити, що у поданні sysmessages нумерація поширюється на весь сервер Якщо два виробника баз даних використовують пересічні повідомлення, то між базами даних не існує поділу Це означає, що перевага не віддається жодному з проектів Друге питання полягає в тому, що при перенесенні бази даних на інший сервер повідомлення також слід переміщати

Таблиця sysmessages містить стовпчики ідентифікатора і тексту повідомлення, рівня небезпеки, а також ознаки протоколювання У той же час рівень небезпеки команди raiserror підставляється замість значення з таблиці SysMessage таким чином, останнє нівелюється

Для управління повідомленнями в програмному коді використовується системна збережена процедура sp_addmessage:

EXEC sp_addmessage 50001, 16, Неможливо оновити% s;

Проекти баз даних можуть бути розгорнуті на різних мовах, і необовязковий параметр @ lang використовується для вибору мови повідомлень про помилки

Якщо повідомлення вже існує, то в виклик збереженої процедури можна додати параметр replace:

EXEC sp_addmessage 50 001, 16,

‘Все ще неможливо оновити% s, @ Replace = Replace;

Щоб переглянути існуючі користувача повідомлення, слід виконати запит до системного поданням sysmessages:

SELECT *

FROM sysmessages

WHERE message_id &gt 50000

Може бути отриманий наступний результат: message_id language_id severity is_event_logged text

50001 1033 16 0 Усе ще неможливо оновити% s

Для переміщення повідомлень між серверами потрібно виконати одну з наступних дій

■ Зберегти сценарій, спочатку використовувався для завантаження повідомлень

■ Використовувати наступний запит для генерування сценарію, добавляющего повідомлення

SELECT Ехес sp_addmessage,

+ Cast(message_id as VARCHAR(7))

+ , + Cast(Severity as VARCHAR(2))

+ , ” + [text] + ”;’

FROM sysmessages

WHERE message_id &gt 50000

Результат буде наступний:

EXEC sp_addmessage, 50001, 16, Все ще неможливо оновити% s;

Щоб видалити повідомлення використовують системну збережену процедуру sp_dropmessage, якої як аргумент передають номер помилки:

Ехес sp_dropmessage 50001

Протоколювання помилок

Ще однією перевагою використання форми Windows команди га is error є можливість протоколювання помилок в журнал подій Windows NT і в журнал подій SQL Server Недоліком журналу подій Windows є те, що ведеться він окремо на кожній робочій станції Незважаючи на те що цей журнал є відмінним місцем для зберігання помилок підключення до сервера, для помилок бази даних він явно не підходить Існують два способи завдання необхідності протоколювання подій

■ Якщо збережені повідомлення створюються за допомогою завдання параметра @ with_log = with_ log або установки прапорця Always log в процесі додавання нового повідомлення у Management Studio, помилки будуть протоколюватися

■ Якщо в команді raiserror вказаний параметр with log, то буде протоколюватися тільки дане повідомлення про помилку

Наприклад, виконання наступної команди raiserror призведе до запису помилки неможливості поновлення в журнал подій:

RAISERROR (Неможливо оновити% s’, 14, 1, Customer)

WITH LOG

Результат буде наступним:

Server: Msg 50000, Level 14, State 1, Line 1 Неможливо оновити Customer

Щоб переглянути помилки в журналі подій (рис 181), виберіть у меню Пуск системи Windows пункт Панель управління ^ Засоби адміністрування ^ Журнал подій (Control Panels Administrative Tools ^ Event Viewer) Запустити перегляд журналу подій можна також з меню Всі програми (Programs)

Журнал SQL Server

SQL Server підтримує декілька файлів журналів При кожному запуску SQL Server створює новий файл журналу SQL Server постійно підтримує сім файлів журналів: шість архівних та один поточний Всі ці журнали перераховані у вікні Object Explorer утиліти Management Studio у вузлі Management ^ SQL Server Logs Двічі клацніть на назві журналу, щоб відкрити вікно перегляду, показане на рис 182 У перегляді вам допоможуть установка фільтру і функція пошуку

Puc 181 Помилка SQL Server у вікні журналу подій Windows Зверніть увагу на те, що в дані про помилку включені імена сервера і бази даних

Puc 182 Перегляд помилок в журналі SQL Server у вікні утиліти Management Studio

БЛОК Catch

Для перехоплення і обробки помилок зазвичай використовують структуру Try Catch У блоці Catch ви можете зробити наступне

1&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp Якщо пакет використовує логічні транзакції (begin tran .. commit tran), то обробник помилки повинен відкотити транзакцію Особисто я рекомендую використовувати відкат як перша дія, щоб зняти всі блокування, встановлені транзакцією

2&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp Якщо помилку виявила логіка збереженої процедури і вона не є помилкою SQL Server, відображуватимете повідомлення про помилку, щоб інформувати кінцевого користувача Якщо помилку виявить SQL Server, то він сам відкриє вікно попередження

3&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp При бажанні зареєструйте помилку в окремій таблиці

4&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp Завершіть виконання пакету Якщо вона сталася в збереженій процедурі, користувача функції або триггере, то завершите їх виконання командою return

У наступному прикладі продемонстровано обробка помилок Якщо помилка повязана з SQL Server і вона виявлена ​​в блоці try, то управління негайно передається в блок catch, в якому вона обробляється:

Begin Try – Код T-SQL End Try Begin Catch

– Код обробки помилок End Catch

Фатальні помилки T-SQL

Якщо виявлена ​​фатальна помилка Т-SQL, то виконання пакету негайно завершується, і вам не надається ніякої можливості переглянути вміст змінної @ @ Еггог, обробити помилку і, можливо, виправити ситуацію

Фатальні помилки зустрічаються досить рідко, тому великих проблем, як правило, не створюють Зазвичай якщо пакет запускається один раз, то він продовжить роботу, якщо, звичайно, не змінюється схема або конфігурація SQL Server Найчастіше фатальні помилки викликані декількома факторами:

■ несумісністю типів даних

■ недоступністю ресурсів SQL Server

■ синтаксичними помилками

■ додатковими настройками SQL Server, несумісними з конкретним завданням

■ відсутністю обєктів або друкарськими помилками в їх іменах

Щоб отримати список більшості повідомлень про фатальні помилки, виконайте наступний запит:

SELECT Error, Severity, Description FROM MasterdboSysMessages WHERE Severity &gt= 19 ORDER BY Severity, Error

Структура try Catch добре справляється з роботою з обробки повсякденних помилок користувача, наприклад з порушенням обмежень І все ж для забезпечення більшої безпеки розробники клієнтських додатків повинні включати обробку помилок в свої програми

Резюме

Мова Т-SQL розширює можливості запитів набором процедурних команд Незважаючи на те що Т-SQL не можна назвати повноцінною мовою програмування, він непогано справляється з роботою Команди пакетів Т-SQL можуть використовуватися у виразах, бути сконцентровані в збережених процедурах, користувальницьких функціях і тригерах

У наступних двох розділах ми продовжимо вивчення мови Т-SQL і розглянемо масові операції і процеси, засновані на обробці окремих рядків За ними підуть глави, присвячені організації пакетів Т-SQL в збережені процедури, функції користувача і тригери

Джерело: Нільсен, Пол Microsoft SQL Server 2005 Біблія користувача : Пер з англ – М: ООО ІД Вільямс , 2008 – 1232 с : Ил – Парал тит англ

Схожі статті:


Сподобалася стаття? Ви можете залишити відгук або підписатися на RSS , щоб автоматично отримувати інформацію про нові статтях.

Коментарів поки що немає.

Ваш отзыв

Поділ на параграфи відбувається автоматично, адреса електронної пошти ніколи не буде опублікований, допустимий HTML: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

*

*