1. Trang chủ
  2. » Công Nghệ Thông Tin

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

10 333 0
Tài liệu đã được kiểm tra trùng lặp

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

THÔNG TIN TÀI LIỆU

Thông tin cơ bản

Định dạng
Số trang 10
Dung lượng 1,13 MB

Các công cụ chuyển đổi và chỉnh sửa cho tài liệu này

Nội dung

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@@errorto see the er

Trang 2

T-SQL Error Handling

IN THIS CHAPTER Legacy error handling Try/catch blocks Rethrowing errors

So 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@@errorto 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

Trang 3

What’s New with Error Handling?

Unfortunately, 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 SQL Server 2005 So, from an adoption

standpoint, it may as well be new

The basic error information system functions, such as@@errorand@@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@@errorsystem function will contain the integer error code for the previous T-SQL statement

A0indicates 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 twoprintcommands demonstrate how

@@erroris reset by every T-SQL command The firstprintcommand displays the success or failure

of the update

The secondprintcommand (results in bold) displays the success or failure of the previousprint

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

Trang 4

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@erras

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@@rowCountsystem function is useful for

checking the effectiveness of the query

The reset issue that affects@@erroralso affects@@rowcount

The following batch uses@@rowcountto check for rows updated The failure results from the

incor-rectWHEREclause condition No row withPersonID = 100exists.@@rowcountis 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;

Trang 5

no rows affected

To capture both the@@errorand the@@rowcountfunctions, use aSELECTstatement with two

variables:

SELECT @err = @@error, @rcount = @@rowcount

Raiserror

To return custom error messages to the calling procedure or front-end application, use theRAISERROR

command Two forms forRAISERRORexist: 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 as16— 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 theRAISERRORcommand:

■ 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 improvedRAISERRORadds parameters for the severity level, state (seldom used),

and message-string arguments:

RAISERROR ( message or number, severity, state, optional arguments ) WITH LOG;

Trang 6

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 yourRAISERRORwill 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%sfor a string and%ifor 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

TheRAISERRORcommand can also pull a message from thesys.messagessystem 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 withsys.messagesstored 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

Trang 7

Thesys.messagestable includes columns for themessage_id,text,severity, and whether

the error should be logged However, the severity of theRAISERRORcommand is used instead of the

severityfrom thesys.messagestable, sosys.messages.severityis moot

To manage messages in code, use thesp_addmessagesystem stored procedure:

EXEC sp_addmessage 50001, 16, ‘Unable to update %s’;

For database projects that may be deployed in multiple languages, the optional@langparameter can be

used to specify the language for the error message

If the message already exists, then areplaceparameter 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 thesys.messagessystem 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 thesp_dropmessagesystem stored procedure with the error number:

EXEC sp_dropmessage 50001;

Trang 8

Logging the error

Another advantage of using the improved form of theRAISERRORcommand 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 theRAISERRORcommand, add theWITH LOGoption:

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 embedded in the error data

Trang 9

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 CATCHis 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 theTRYblock and immediately jump to theCATCHblock to

handle the error:

BEGIN TRY

Trang 10

<SQL code>;

END TRY

BEGIN CATCH

<error handling code>;

END CATCH;

If theTRYblock of code executes without any error, then theCATCHcode is never executed, and

execution resumes after theCATCHblock:

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 theTRYblock until theRAISERROR’s simulated

error, which sends the execution down to theCATCHblock The entireCATCHblock is executed

Following execution of the CATCHblock, 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 theCATCHblocks Within the

CATCHblock, 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

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

TỪ KHÓA LIÊN QUAN