Как лучше всего использовать обработку ошибок SQL Server T-SQL? [закрытый]
у нас есть большое приложение, в основном написанное на SQL Server 7.0, где все вызовы базы данных относятся к хранимым процедурам. теперь мы запускаем SQL Server 2005, который предлагает больше возможностей T-SQL.
после почти каждого выбора, вставки, обновления и удаления @@ROWCOUNT и @@ERROR попадают в локальные переменные и оцениваются для проблем. Если есть проблема, делается следующее:
- выходной параметр сообщения об ошибке set
- откат (при необходимости) делается
- информация записывается (вставка) в таблицу журнала
- возврат с номером ошибки, уникальным для этой процедуры (положительный, если фатальный, отрицательный-предупреждение)
все они не проверяют строки (только когда это известно), а некоторые отличаются более или менее информацией журнала/отладки. Кроме того, логика строк является чем-то, отделенным от логики ошибок (при обновлениях, где поле параллелизма проверяется в предложении WHERE, rows=0 означает кто-то еще обновил данные). Однако вот довольно общий пример:
SELECT, INSERT, UPDATE, or DELETE
SELECT @Error=@@ERROR, @Rows=@@ROWCOUNT
IF @Rows!=1 OR @Error!=0
BEGIN
SET @ErrorMsg='ERROR 20, ' + ISNULL(OBJECT_NAME(@@PROCID), 'unknown')
+ ' - unable to ???????? the ????.'
IF @@TRANCOUNT >0
BEGIN
ROLLBACK
END
SET @LogInfo=ISNULL(@LogInfo,'')+'; '+ISNULL(@ErrorMsg,'')+
+ ' @YYYYY=' +dbo.FormatString(@YYYYY)
+', @XXXXX=' +dbo.FormatString(@XXXXX)
+', Error=' +dbo.FormatString(@Error)
+', Rows=' +dbo.FormatString(@Rows)
INSERT INTO MyLogTable (...,Message) VALUES (....,@LogInfo)
RETURN 20
END
Я рассматриваю замену того, как мы это делаем с помощью TRY-CATCH T-SQL. Я читал о попробовать...Поймать (язык Transact-SQL) в синтаксис, так что не просто опубликовать резюме. Я ищу любые хорошие идеи и как лучшие сделать или улучшить наши методы обработки ошибок. Это не должно быть Try-Catch, просто любое хорошее или лучшее использование практики ошибки T-SQL обращение.
4 ответов
вы должны прочитать это:
http://www.sommarskog.se/error-handling-I.html
Я не могу рекомендовать эту ссылку достаточно высоко. Немного длинновато, но в хорошем смысле.
на фронте есть отказ от ответственности, что он был первоначально написан для SQL Server 2000, но он охватывает новые возможности обработки ошибок try/catch в SQL Server 2005+.
в настоящее время мы используем этот шаблон для любых запросов, которые мы выполняем (вы можете оставить материал транзакции, если он вам не нужен, например, в инструкции DDL):
BEGIN TRANSACTION
BEGIN TRY
// do your SQL statements here
COMMIT TRANSACTION
END TRY
BEGIN CATCH
SELECT
ERROR_NUMBER() AS ErrorNumber,
ERROR_SEVERITY() AS ErrorSeverity,
ERROR_STATE() AS ErrorState,
ERROR_PROCEDURE() AS ErrorProcedure,
ERROR_LINE() AS ErrorLine,
ERROR_MESSAGE() AS ErrorMessage
ROLLBACK TRANSACTION
END CATCH
конечно, вы можете легко вставить поймал исключение в таблицу журнала ошибок.
Она работает очень хорошо для нас. Вероятно, вы даже можете автоматизировать некоторые преобразования из старых хранимых процессоров в новый формат, используя генерацию кода (например, CodeSmith) или некоторый пользовательский код c#.
нет набора в камне лучших практик для обработки ошибок. Все сводится к тому, что ваши потребности и быть последовательным.
вот пример таблицы и хранимой процедуры, в которой хранятся номера телефонов.
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
SET ANSI_PADDING ON
GO
CREATE TABLE [dbo].[Phone](
[ID] [int] IDENTITY(1,1) NOT NULL,
[Phone_Type_ID] [int] NOT NULL,
[Area_Code] [char](3) NOT NULL,
[Exchange] [char](3) NOT NULL,
[Number] [char](4) NOT NULL,
[Extension] [varchar](6) NULL,
CONSTRAINT [PK_Phone] PRIMARY KEY CLUSTERED
(
[ID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO
SET ANSI_PADDING OFF
GO
/**/
CREATE PROCEDURE [dbo].[usp_Phone_INS]
@Customer_ID INT
,@Phone_Type_ID INT
,@Area_Code CHAR(3)
,@Exchange CHAR(3)
,@Number CHAR(4)
,@Extension VARCHAR(6)
AS
BEGIN
SET NOCOUNT ON;
DECLARE @Err INT, @Phone_ID INT
BEGIN TRY
INSERT INTO Phone
(Phone_Type_ID, Area_Code, Exchange, Number, Extension)
VALUES
(@Phone_Type_ID, @Area_Code, @Exchange, @Number, @Extension)
SET @Err = @@ERROR
SET @Phone_ID = SCOPE_IDENTITY()
/*
Custom error handling expected by the application.
If Err = 0 then its good or no error, if its -1 or something else then something bad happened.
*/
SELECT ISNULL(@Err,-1) AS Err, @Phone_ID
END TRY
BEGIN CATCH
IF (XACT_STATE() <> 0)
BEGIN
ROLLBACK TRANSACTION
END
/*
Add your own custom error handling here to return the passed in paramters.
I have removed my custom error halding code that deals with returning the passed in parameter values.
*/
SELECT ERROR_NUMBER() AS Err, ISNULL(@Phone_ID,-1) AS ID
END CATCH
END
похоже, у вас уже есть очень хорошая ручка. Я подозреваю, что вы делаете больше, чем 95% программистов SQL.
вы должны найти интересную информацию здесь:
- обнаружение и сообщение об ошибках в хранимых процедурах-Часть 1: SQL Server 2000
- обнаружение и сообщение об ошибках в хранимых процедурах-Часть 2: SQL Server 2005 TRY-CATCH Blocks*
один [несвязанное] предложение: начните использовать ' ' вместо '!='.
[* SQL Junkies ушел, поэтому вторая статья недоступна. Я попытаюсь переиздать его где-нибудь и обновить ссылку.]