|
Программирование >> Программирование баз данных
USE AdventureWorks .GO INSERT INTO Sales.StoreContact (CustomerlD, ContactID, ContactTypelD) VALUES (0, 0, 11) СУБД SQL Server не выполнит эту операцию вставки, поскольку на обоих столбцах, CustomerlD и ContactID, задано ограничение FOREIGN KEY, которое ссылается на первичный ключ в других таблицах. В данном случае в этих двух таблицах отсутствуют согласующиеся строки, поэтому строка, которую мы пытаемся вставить в таблицу Sales. StoreContact, нарушает оба ограничения внешнего ключа и отвергается: Msg 547, Level 16, State О, Line 2 The INSERT statement conflicted with the FOREIGN KEY constraint FK Individual Contact ContactID . The conflict occurred in database AdventureWorks , table Person.Contact , column ContactID. The statement has been terminated. Обратите внимание на то, что сообщение об ошибке, сформированное в данном случае, имеет определенный код- 547. Этим можно воспользоваться для обработки ошибок. Следует отметить, что сообщение об ошибке, выработанное СУБД SQL Seruer, соответствует только первому нарушению ограничения внешнего ключа, поскольку СУБД, обнаружив это нарушение, определяет, какой оператор стал его причиной, и прекращает дальнейилее выполнение этого оператора, А после того, как первая ошибка будет исправлена, повторный вызов на выполнение того же оператора приведет к обнаружению второго нарушения, и снова возникнет ошибка. Использование системной переменной @@error Напомним, что системная переменная @@ERROR содержит номер ошибки, обнаруженной при выполнении последнего по времени оператора T-SQL. Если значение этой переменной равно нулю, то можно сделать вывод, что ошибки не обнаружены. В этом проявляется определенная аналогия с функцией ERROR NUMBER (), которая рассматривалась в предыдущей главе в связи с первым упоминанием блоков TRY/CATCH. Дело в том, что возвращаемое значение функции ERROR NUMBER () является действительным только в пределах блока CATCH и остается одинаковым, а значение переменной @@ERROR переустанавливается после вьшолнения каждого очередного оператора. Особое внимание следует обратить на то, что вьшолнение каждого нового оператора приводит к переопределению значения системной переменной ®@ERROR. Это означает, что если требуется отложить анализ текущего значения или воспользоваться им в нескольких местах кода, то необходимо перенести его на хранение в какое-то другое место, например, в локальную переменную, предназначенную специально для этой цели. Воспользуемся значением @@ERROR, полученным при выполнении приведенного выше оператора INSERT: USE AdventureWorks GO DECLARE ©Error int -- Фиктивный оператор INSERT; значения CustomerlD или ContactID, равные О, не -- могут применяться. При попытке применить любое из этих значений может -- возникнуть ошибка INSERT INTO Sales.Individual (CustomerlD, ContactID) VALUES (0,0) -- Передать значение кода ошибки на хранение. Дело в том, что после выполения -- текущего оператора системной переменной ©©Error будет присвоен новый код ошибки, относящийся именно к нему SELECT ©Error = ©©ERROR -- Вывод пустой разделительной строки PRINT -- Значение переменной, предназначенной для хранения информации, является таким, -- как и следовало ожидать PRINT The Value of ©Error is + CONVERT(varchar, ©Error) -- Значение переменной ©©ERROR переустановлено и снова стало равным нулю PRINT The Value of ©©ERROR is + CONVERT(varchar, ©©ERROR) После этого вызовем на выполнение подготовленный сценарий и проверим, как изменяется значение @@error: Msg 547, Level 16, State О, Line б The INSERT statement conflicted with the FOREIGN KEY constraint FK Individual Contact ContactID . The conflict occurred in database AdventureWorks , table Person.Contact , column ContactID. The statement has been terminated. The Value of ©Error is 547 The Value of ©©ERROR is 0 Эти результаты наглядно демонстрируют, насколько важно сохранить текущее значение @@error. Первое сообщение об ошибке является по своему характеру исключительно информационным. СУБД SQL Server активизирует эту ошибку, но не завершает аварийно выполнение кода. Единственной частью данного сообщения, к которой может быть получен доступ к хранимой процедуре, является номер ошибки. Но этот номер ошибки сохраняется в системной переменной @@error лишь до вызова на выполнение следующего оператора T-SQL, а после этого исчезает. Обратите внимание на то, что ©Error и @@ERROR - две отдельные и различимые переменные, которые могут использоваться в коде независимо друг от друга. Это обусловлено не только тем, что имена этих переменных отличаются регистром букв. (Чувствительность к регистру в именах переменных может зависеть от настройки конфигурации сервера.) Различие между переменными в данном случае определяется тем, какую область определения имеет та и другая переменная. В состав первого и второго имени входят соответственно символы @ и @@, поэтому различия между указанными именами состоят лишь в том, что они содержат в качестве префикса разное количество символов @. В частности, блоки try/catch позволяют обрабатывать ошибки таких типов, появление которых в предыдущих версиях приводило к аварийному завершению вьшолнения сценария. Несмотря на сказанное, блоки try/catch становятся неприменимыми, если требуется обеспечить обратную совместимость с SQL Server 2000 или более ранними версиями, поэтому кратко рассмотрим, как используется системная переменная@@error. При этом в качестве примеров рассмотрим две небольшие процедуры. Назначение этих процедур состоит не в том, чтобы продемонстрировать что-то новое по сравнению со сценариями или хранимыми процедурами, которые были описаны выше в данной книге; скорее они позволяют определить, в каких условиях встроенные средства проверки ошибок действуют успешно и в каких не позволяют добиться требуемых результатов (нас особенно интересуют ситуации, в которых встроенные средства обработки не позволяют обрабатывать ошибки, а блоки try/catch позволяют). Прежде всего заслуживает внимания пример применения средств контроля ссылочной целостности, который рассматривался выше в данной главе: USE AdventureWorks GO INSERT INTO Sales.StoreContact (CustomerlD, ContactID, ContactTypelD) VALUES (0, 0, 11) Напомним, что попытка вьшолнения этого сценария закончилась получением со-обще1шя об ошибке с кодом 547. Данная ошибка относится к категории тех ошибок, которые могут быть перехвачены в коде. Как было показано выше, в простом сценарии перехват этой ошибки удается выполнить успешно, но данный раздел посвящен описанию хранимых процедур, поэтому рассмотрим, сможем ли мы добиться той же цели при использовании аналогичных средств в хранимой процедуре: USE AdventureWorks GO CREATE PROC spInsertValidatedStoreContact ©CustomerlD int, ©ContactID int, ©ContactTypelD int BEGIN DECLARE ©Error int Использование системной переменной @@error в хранимой процедуре Практика показывает, что обычно оправдывается следующее предположение: если в исходном коде приложения используется системная переменная @@error, то скорее всего в нем вряд ли удастся встретить блоки try/catch. Если причиной отказа от использования блоков try/catch не является стремление обеспечить обратную совместимость, то автор настоятельно рекомендует коренным образом пересмотреть сложившийся подход и перейти к использованию блоков try/catch, поскольку с их помощью могут быть созданы намного более удобные и в целом гораздо более качественные средства обработки ошибок.
|
© 2006 - 2024 pmbk.ru. Генерация страницы: 0
При копировании материалов приветствуются ссылки. |