Подтвердить что ты не робот

Какова наилучшая практика использования ошибок SQL Server T-SQL?

У нас есть большое приложение, в основном написанное на SQL Server 7.0, где все вызовы базы данных хранятся в хранимых процедурах. Теперь мы запускаем SQL Server 2005, который предлагает больше возможностей T-SQL.

После почти всех SELECT, INSERT, UPDATE и DELETE, @@ROWCOUNT и @@ERROR попадают в локальные переменные и оцениваются по проблемам. Если возникла проблема, выполните следующие действия:

  • установлен параметр вывода сообщения об ошибке
  • откат (если необходимо)
  • информация записывается (INSERT) для записи таблицы
  • return с номером ошибки, уникальным для этой процедуры (положительный, если фатальный, отрицательный - предупреждение)

Все они не проверяют строки (только когда это известно), а некоторые отличаются более или менее информацией об ошибках/отладочной информации. Кроме того, логика строк когда-то расщепляется от логики ошибок (при обновлениях, где поле concurrency отмечено в предложении WHERE, rows = 0 означает, что кто-то еще обновил данные). Однако здесь довольно общий пример:

SELECT, INSERT, UPDATE, or DELETE

SELECT @[email protected]@ERROR, @[email protected]@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. Я читал о синтаксисе TRY... CATCH (Transact-SQL), поэтому не просто публикуйте некоторые сводки об этом. Я ищу любые хорошие идеи и как лучший делать или улучшать наши методы обработки ошибок. Это не должно быть Try-Catch, просто любая хорошая или лучшая практика использования обработки ошибок T-SQL.

4b9b3361

Ответ 1

Вы должны прочитать следующее:

http://www.sommarskog.se/error-handling-I.html

Я не могу рекомендовать эту ссылку достаточно высоко. Это немного длиннее, но в хорошем смысле.

Там есть оговорка о том, что она была первоначально написана для SQL Server 2000, но она также охватывает новые возможности обработки ошибок try/catch в SQL Server 2005+.

Ответ 2

В настоящее время мы используем этот шаблон для любых выполняемых нами запросов (вы можете оставить материал Transaction, если он вам не нужен, например, в заявлении 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

Конечно, вы можете легко вставить исключенное исключение в свою таблицу журнала ошибок.

Это хорошо работает для нас. Возможно, вы, возможно, даже автоматизировали некоторые преобразования из старых хранимых procs в новый формат с использованием Code Generation (например, CodeSmith) или какой-то пользовательский код С#.

Ответ 3

В обработке ошибок не существует набора наилучших методов управления камнем. Все сводится к тому, каковы ваши потребности и быть последовательными.

Ниже приведен пример таблицы и хранимой процедуры, в которой хранятся номера телефонов.

 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

Ответ 4

Похоже, вы уже очень хорошо справляетесь с этим. Я подозреваю, что вы делаете более 95% программистов SQL.

Здесь вы найдете интересную информацию:

Одно [несвязанное] предложение: начните использовать '< > ' вместо '! ='.

[* SQL Junkies ушел, поэтому вторая статья недоступна. Я попытаюсь переиздать его и обновить ссылку.]