Jaka jest najlepsza praktyka obsługi błędów SQL Server T-SQL? [zamknięte]
Mamy dużą aplikację napisaną głównie w SQL Server 7.0, gdzie wszystkie wywołania bazy danych są do procedur składowanych. obecnie uruchamiamy SQL Server 2005 , który oferuje więcej funkcji T-SQL.
Po prawie każdym SELECT, INSERT, UPDATE I DELETE, @@ROWCOUNT i @ @ ERROR są przechwytywane do zmiennych lokalnych i oceniane pod kątem problemów. W przypadku wystąpienia problemu wykonujemy następujące czynności:
- parametr wyjściowy Komunikatu o błędzie jest ustawiony
- rollback (w razie potrzeby) jest done
- info jest zapisywane (INSERT) do tabeli log
- powrót z numerem błędu, unikalnym dla tej procedury (dodatni, jeśli śmiertelny, ujemny to Ostrzeżenie)
Wszystkie nie sprawdzają wierszy (tylko wtedy, gdy są znane), a niektóre różnią się mniej lub bardziej informacjami log/debug. Również logika rows jest oddzielona od logiki błędu(przy aktualizacjach, gdzie pole współbieżności jest zaznaczone w klauzuli WHERE, rows=0 oznacza, że ktoś inny zaktualizował dane). Jednak tutaj jest dość ogólny przykład:
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
Szukam zastąpienia tego, jak to robimy, try-CATCH T-SQL. Czytałem o próbie ...CATCH (Transact-SQL) składnia, więc nie po prostu pisać jakieś podsumowanie tego. Szukam dobrych pomysłów i jak najlepiej zrobić lub poprawić nasze metody obsługi błędów. Nie musi to być Try-Catch, tylko dobre lub najlepsze wykorzystanie obsługi błędów T-SQL.
4 answers
Powinieneś przeczytać to:
Http://www.sommarskog.se/error-handling-I.html
Nie polecam tego linku. Jest trochę długa, ale w dobry sposób.
Z przodu znajduje się zastrzeżenie, że pierwotnie został napisany dla SQL Server 2000, ale obejmuje również nowe możliwości obsługi błędów try/catch w SQL Server 2005+.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-06-08 17:56:01
Obecnie używamy tego szablonu dla wszelkich zapytań, które wykonujemy (możesz pominąć transakcję, jeśli nie potrzebujesz jej np. w instrukcji 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
Oczywiście możesz łatwo wstawić przechwycony wyjątek do tabeli dziennika błędów.
To działa naprawdę dobrze dla nas. Prawdopodobnie możesz nawet zautomatyzować część konwersji ze starych przechowywanych procesorów do nowego formatu za pomocą generowania kodu (np. CodeSmith) lub niestandardowego kodu C#.Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-07-07 09:20:59
Nie ma zestawu najlepszych praktyk stone do obsługi błędów. Wszystko sprowadza się do tego, jakie są Twoje potrzeby i bycia konsekwentnym.
Oto przykład tabeli i procedury składowanej, która przechowuje numery telefonów.
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
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-04-07 15:25:16
Wygląda na to, że dobrze sobie z tym radzisz. Podejrzewam, że robisz więcej niż 95% programistów SQL tam.
Tutaj znajdziesz kilka ciekawych informacji:
- wykrywanie i raportowanie błędów w procedurach składowanych-Część 1: SQL Server 2000
- wykrywanie i raportowanie błędów w procedurach składowanych-część 2: SQL Server 2005 TRY-CATCH Blocks *
Jedna [niezwiązana] sugestia: zacznij używać ' ' zamiast '!='.
[*SQL Junkies odszedł, więc drugi artykuł nie jest dostępny. Postaram się to gdzieś opublikować i zaktualizować link.]
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-09-30 17:53:42