Hướng dẫn học Microsoft SQL Server 2008 part 64 pdf

10 329 0
Hướng dẫn học Microsoft SQL Server 2008 part 64 pdf

Đang tải... (xem toàn văn)

Thông tin tài liệu

Nielsen c22.tex V4 - 07/23/2009 4:52pm Page 592 www.getcoolebook.com Nielsen c23.tex V4 - 07/23/2009 4:53pm Page 593 T-SQL Error Handling IN THIS CHAPTER Legacy error handling Try/catch blocks Rethrowing errors S o an atom goes into a bar and says to the barkeeper, ‘‘Hey, I think I’ve lost an electron.’’ ‘‘Are you sure?’’ asks the barkeep. ‘‘Of course, in fact, I’m positive.’’ Lame, I know, but it’s my favorite geek joke; I couldn’t help it. Back to SQL, despite our best efforts, any application can lose an electron every once in a while — the trick is to handle it in a positive way. Of course, all robust programming languages provide some method for trapping, logging, and handling errors. In this area, T-SQL has a sad history (almost as sad as that joke), but it’s made significant progress with SQL Server 2005. There are two distinctly different ways to code error handling with SQL Server: ■ Legacy error handling is how it’s been done since the beginning of SQL Server, using @@error to see the error status of the previous SQL statement. ■ Try/catch was introduced in SQL Server 2008, bringing SQL Server into the 21st century. Legacy Error Handling Historically, T-SQL error handling has been tedious at best. I’d prefer to not even include this legacy method of handling errors, but I’m sure you’ll see it in old code, so it must be covered. 593 www.getcoolebook.com Nielsen c23.tex V4 - 07/23/2009 4:53pm Page 594 Part IV Developing with SQL Server What’s New with Error Handling? U nfortunately, there is nothing new in 2008 when it comes to error handling. However, when performing code reviews for third-party software vendors, I rarely see production code with any error handling, much less the improved try catch, which was introduced in S QL Server 2005. So, from an adoption standpoint, it may as well be new. The basic error information system functions, such as @@error and @@rowcount, contain the status for the previous T-SQL command in the code. This means that the legacy method of error handling must examine T-SQL’s system functions and handle the error after each SQL statement that might potentially encounter an error. @@error system function The @@error system function will contain the integer error code for the previous T-SQL statement. A 0 indicates success. The difficulty is that @@error, unlike other languages that hold the last error in a variable until another error occurs, is updated for every command, so even testing its value updates it. The following code sample attempts to update the primary key to a value already in use. This violates the foreign key constraint and generates an error. The two print commands demonstrate how @@error is reset by every T-SQL command. The first print command displays the success or failure of the update. The second print command (results in bold) displays the success or failure of the previous print command: USE Family; UPDATE Person SET PersonID = 1 Where PersonID = 2; Print @@error; Print @@error; Result: Msg 2627, Level 14, State 1, Line 2 Violation of PRIMARY KEY constraint ‘PK Person AA2FFB847F60ED59’. Cannot insert duplicate key in object ‘dbo.Person’. The statement has been terminated. 2627 0 594 www.getcoolebook.com Nielsen c23.tex V4 - 07/23/2009 4:53pm Page 595 T-SQL Error Handling 23 The solution to the ‘‘last error status’’ problem is to save the error status to a local variable. This solution retains the error status so it may be properly tested and then handled. The following batch uses @err as a temporary error variable: USE Family; DECLARE @err INT; UPDATE Person SET PersonID = 1 Where PersonID = 2 SET @err = @@error; IF @err <> 0 BEGIN error handling code PRINT @err; END; Result: Msg 2627, Level 14, State 1, Line 2 Violation of PRIMARY KEY constraint ‘PK Person AA2FFB847F60ED59’. Cannot insert duplicate key in object ‘dbo.Person’. The statement has been terminated. 2627 @@rowcount system function Another way to determine whether the query was a success is to check the number of rows affected. Even if no error was generated, it’s possible that the data didn’t match and the operation failed, which might indicate a data, logic, or business rule problem. The @@rowCount system function is useful for checking the effectiveness of the query. The reset issue that affects @@error also affects @@rowcount. The following batch uses @@rowcount to check for rows updated. The failure results from the incor- rect WHERE clause condition. No row with PersonID = 100 exists. @@rowcount is used to detect the query failure: USE FAMILY; UPDATE Person SET LastName = ‘Johnson’ WHERE PersonID = 100; IF @@rowCount = 0 BEGIN error handling code PRINT ‘no rows affected’; END; 595 www.getcoolebook.com Nielsen c23.tex V4 - 07/23/2009 4:53pm Page 596 Part IV Developing with SQL Server Result: no rows affected To capture both the @@error and the @@rowcount functions, use a SELECT statement with two variables: SELECT @err = @@error, @rcount = @@rowcount Raiserror To return custom error messages to the calling procedure or front-end application, use the RAISERROR command. Two forms for RAISERROR exist: a legacy simple form and the recommended complete form. The simple raiserror form The simple form, which dates from the Sybase days, passes only a hard-coded number and message. The severity level is always passed back as 16 — user error severe: RAISERROR ErrorNumber ErrorMessage; For example, this code passes back a simple error message: RAISERROR 5551212 ‘Unable to update customer.’; Result: Msg 5551212, Level 16, State 1, Line 1 ’Unable to update customer.’ The simple form is deprecated and will be removed in a future version of SQL Server. I don’t recommend writing new code using this form — it’s included here only in case you see this form in legacy code. The improved raiserror form The improved form (introduced back in SQL Server 7) incorporates the following four useful features into the RAISERROR command: ■ Specifies the severity level ■ Dynamically modifies the error message ■ Uses serverwide stored messages ■ May optionally log the error to the event log The syntax for the improved RAISERROR adds parameters for the severity level, state (seldom used), and message-string arguments: RAISERROR ( message or number, severity, state, optional arguments ) WITH LOG; 596 www.getcoolebook.com Nielsen c23.tex V4 - 07/23/2009 4:53pm Page 597 T-SQL Error Handling 23 Error severity Windows has established standard error-severity codes, listed in Table 23-1. The other severity codes are reserved for Microsoft’s use. In any case, the severity code you’ll use for your RAISERROR will almost always be 16. TABLE 23-1 Available Severity Codes Severity Code Description 10 Status message: Does not raise an error, but returns a message, such as a PRINT statement 11–13 No special meaning 14 Informational message 15 Warning message: Something may be wrong 16 Critical error: The procedure failed Adding variable parameters to messages The error message can be a fixed-string message or the error number of a stored message. Either type can work with optional arguments. The arguments are substituted for placeholders within the error message. While several types and options are possible, the placeholders I find useful are %s for a string and %i for a signed integer. The following example uses one string argument: RAISERROR (’Unable to update %s.’, 14, 1, ‘Customer’); Result: Msg 50000, Level 14, State 1, Line 1 Unable to update Customer. Stored messages The RAISERROR command can also pull a message from the sys.messages system view. Message numbers 1–50,000 are reserved for Microsoft. Higher message numbers are available for user-defined messages. The benefit of using stored messages is that all messages are forced to become consistent and numbered. Note that with sys.messages stored messages, the message-number scheme is serverwide. If two ven- dors, or two databases, use overlapping messages, then no division exists between databases, and there’s no solution beyond recoding all the error handling on one of the projects. The second issue is that when migrating a database to a new server, the messages must also be moved. 597 www.getcoolebook.com Nielsen c23.tex V4 - 07/23/2009 4:53pm Page 598 Part IV Developing with SQL Server The sys.messages table includes columns for the message_id, text, severity, and whether the error should be logged. However, the severity of the RAISERROR command is used instead of the severity from the sys.messages table, so sys.messages.severity is moot. To manage messages in code, use the sp_addmessage system stored procedure: EXEC sp_addmessage 50001, 16, ‘Unable to update %s’; For database projects that may be deployed in multiple languages, the optional @lang parameter can be used to specify the language for the error message. If the message already exists, then a replace parameter must be added to the system stored procedure call, as follows: EXEC sp_addmessage 50001, 16, ‘Update error on %s’, @replace = ‘replace’; To view the existing custom messages, select from the sys.messages system view: SELECT * FROM sys.messages WHERE message_id > 50000; Result: message_id language_id severity is_event_logged text 50001 1033 16 0 Unable to update %s To move messages between servers, do one of the following: ■ Save the script that was originally used to load the messages. ■ Use the Transfer Error Messages Task in Integration Services. ■ Use the following query to generate a script that adds the messages: SELECT ‘EXEC sp_addmessage, ’ + CAST(message_id AS VARCHAR(7)) + ‘, ’ + CAST(severity AS VARCHAR(2)) + ‘, ’‘’ + [text] + ‘’‘;’ FROM sys.messages WHERE message_id > 50000; Result: EXEC sp_addmessage, 50001, 16, ‘Unable to update %s’; To drop a message, use the sp_dropmessage system stored procedure with the error number: EXEC sp_dropmessage 50001; 598 www.getcoolebook.com Nielsen c23.tex V4 - 07/23/2009 4:53pm Page 599 T-SQL Error Handling 23 Logging the error Another advantage of using the improved form of the RAISERROR command is that it can log the error to the Windows Application event log and the SQL Server event log. The downside to logging to the Application event log is that it’s stored on individual workstations. While the Application event log is a great place to log front-end ‘‘unable to connect’’ errors, it’s an inconvenient place to store database errors. To specify that an event should be logged from the RAISERROR command, add the WITH LOG option: RAISERROR (’Unable to update %s.’, 14, 1, ‘Customer’) WITH LOG Result: Server: Msg 50000, Level 14, State 1, Line 1 Unable to update Customer. To view errors in the Application event log (see Figure 23-1), select Control Panel ➪ Administrative Tools ➪ Event Viewer. An Event Viewer is also located in Control Panel ➪ Administrative Tools. FIGURE 23-1 A SQL Server raiserror error in the Windows Application event log. Notice that the server and database name are e mbedded in the error data. 599 www.getcoolebook.com Nielsen c23.tex V4 - 07/23/2009 4:53pm Page 600 Part IV Developing with SQL Server SQL Server log SQL Server also maintains a series of log files. Each time SQL Server starts, it creates a new log file. Six archived copies of the last log files are retained, for a total of seven log files. Management Studio’s Object Explorer in the Management ➪ SQL Server Logs node lists the logs. Double-clicking a log opens SQL Server’s very cool Log File Viewer, shown in Figure 23-2. It’s worth exploring, as it has a filter and search capabilities. FIGURE 23-2 Viewing an error in the SQL Server log using Management Studio Try Catch TRY CATCH is a standard method of trapping and handling errors that .NET programmers have enjoyed for years. The basic idea is that if SQL Server encounters any errors when it tries to execute a block of code, it will stop execution of the TRY block and immediately jump to the CATCH block to handle the error: BEGIN TRY 600 www.getcoolebook.com Nielsen c23.tex V4 - 07/23/2009 4:53pm Page 601 T-SQL Error Handling 23 <SQL code>; END TRY BEGIN CATCH <error handling code>; END CATCH; If the TRY block of code executes without any error, then the CATCH code is never executed, and execution resumes after the CATCH block: BEGIN TRY SELECT ‘Try One’; RAISERROR(’Simulated Error’, 16, 1); Select ‘Try Two’; END TRY BEGIN CATCH SELECT ‘Catch Block’; END CATCH; SELECT ‘Post Try’; Result: Try One Catch Block Post Try (1 row(s) affected) Walking through this example, SQL Server executes the TRY block until the RAISERROR’s simulated error, which sends the execution down to the CATCH block. The entire CATCH block is executed. Following execution of the CATCH block, execution continues with the next statement, SELECT ‘Post Try’ . The T-SQL compiler treats the END TRY BEGIN CATCH combination as a single contigu- ous command. Any other statements, a batch terminator ( go), or a statement terminator (;) between these two commands will cause an untrapped error. END TRY must be followed immediately by a BEGIN CATCH. Catch block When an error does occur, the best way to trap and handle it is in the CATCH blocks. Within the CATCH block, you want to do the following: 1. If the batch is using logical transactions ( BEGIN TRAN/COMMIT TRAN), then, depending on the error and situation, the error handler might need to roll back the transaction. If this is 601 www.getcoolebook.com . c23.tex V4 - 07/23/2009 4:53pm Page 600 Part IV Developing with SQL Server SQL Server log SQL Server also maintains a series of log files. Each time SQL Server starts, it creates a new log file. Six. done since the beginning of SQL Server, using @@error to see the error status of the previous SQL statement. ■ Try/catch was introduced in SQL Server 2008, bringing SQL Server into the 21st century. Legacy. area, T -SQL has a sad history (almost as sad as that joke), but it’s made significant progress with SQL Server 2005. There are two distinctly different ways to code error handling with SQL Server: ■

Ngày đăng: 04/07/2014, 09:20

Tài liệu cùng người dùng

  • Đang cập nhật ...

Tài liệu liên quan