0% found this document useful (0 votes)
4 views42 pages

CH 08

Uploaded by

vuthnarak2005
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
4 views42 pages

CH 08

Uploaded by

vuthnarak2005
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 42

Transactions and Error Handling

Transactions and
Error Handling
Objectives
• Explore transaction fundamentals in SQL Server 2005.
• Understand the types of errors that can occur and how to handle them.
• Learn how to avoid blocking and deadlocks in transactions.
• Create explicit transactions.
• Create stored procedures using @@ERROR to handle errors.
• Use TRY/CATCH error handling.
• Create user-defined errors.
• Explore uncommittable transactions with XACT_STATE.

The files associated with this chapter are located in the following folder:
{Install Folder}\Transactions
This chapter’s lab does not include additional files.

Microsoft SQL Server 2005 8-1


Copyright © by Application Developers Training Company
All rights reserved. Reproduction is strictly prohibited.
Transactions and Error Handling

Transaction Concepts
Simply put, a transaction is a collection of tasks that perform as a single unit of
work. In database terms, all parts of the transaction must all be saved to the
database, or all must be abandoned. Executing multiple tasks within the scope
of a single transaction enforces the connection between those tasks. If one task
fails, then all tasks are rolled back.

As a programmer, you are responsible for how transactions in your


applications interact with SQL Server. That means starting and ending
transactions at points that enforce the logical consistency of the data relative to
any business rules that may apply. At that point, SQL Server takes over,
ensuring the physical integrity of each transaction by providing locking
facilities, logging, and transaction management features.

Passing the ACID Test


To ensure predictable behavior, all transactions must possess the basic ACID
properties (Atomic, Consistent, Isolated, and Durable).

• Atomic: A transaction must work as a unit, which is either fully


committed or fully abandoned when complete.
• Consistent: All data must be in a consistent state when the transaction
is complete. All data integrity rules must be enforced and all internal
storage mechanisms must be correct when the transaction is complete.
• Isolated: All transactions must be independent of the data operations
of other concurrent transactions. Concurrent transactions can only see
data before other operations are complete or after other transactions
are complete.
• Durable: After the transaction is complete, the effects are permanent
even in the event of system failure.
The ACID test is part of the ANSI SQL-92 standard, and is fully supported in
SQL Server, which ensures that all transactions meet the ACID test by
supplying the following features:

• Locking facilities that preserve transaction isolation.


• Logging facilities that ensure transaction durability. Even if the server
hardware, operating system, or SQL Server itself fails, SQL Server
uses the transaction logs, upon restart, to automatically roll back any
uncompleted transactions to the point of the system failure.
• Transaction management features that enforce transaction atomicity
and consistency. After a transaction starts, it must complete
successfully, or SQL Server undoes all of the data modifications that
occurred since the transaction started.

8-2 Microsoft SQL Server 2005


Copyright © by Application Developers Training Company
All rights reserved. Reproduction is strictly prohibited.
Transaction Concepts

Transaction Types
SQL Server supports three types of transactions:

• Explicit transactions. Must be started by issuing a BEGIN


TRANSACTION statement. The COMMIT statement commits an
explicit transaction, and the ROLLBACK statement rolls it back. The
@@TRANCOUNT system function tracks the number of open
transactions.
• Autocommit transactions. The default mode for SQL Server. All
individual statements submitted to SQL Server are automatically
committed when they are complete.
• Implicit transactions. A mode in which SQL Server operates. You
control this mode by using the Transact-SQL SET
IMPLICIT_TRANSACTIONS statement. The ON setting causes each
statement to automatically start a new transaction. The OFF setting
(the default) requires you to end each transaction with a COMMIT or
ROLLBACK statement.
By default, transactions are managed at the connection level. When a
transaction is started on a connection, all Transact-SQL statements executed on
that connection are part of the transaction until the transaction ends.

Each transaction must end with either a COMMIT or a ROLLBACK


statement. A COMMIT statement guarantees that all modifications are
permanent. The ROLLBACK statement backs out all modifications made in
the transaction by returning the data to the state it was in at the start of the
transaction. Both COMMIT and ROLLBACK free the locks and resources that
the transaction used.

How Autocommit Works

Autocommit is the default mode for working with transactions. A developer does not
need to issue any transactional statements⎯SQL Server takes care of everything
behind the scenes. If a statement completes successfully, it is committed; if it
encounters any error, it is rolled back. A connection to an instance of the Database
Engine operates in Autocommit mode whenever explicit or implicit transactions do not
override this default mode. Autocommit mode is also the default mode for ADO, OLE
DB, ODBC, and DB-Library.

Isolation Levels and Transactions


The default READ COMMITTED isolation level is in effect with autocommit
transactions. This ensures that every transaction meets the requirements of the
ACID test without requiring extra code. READ COMMITTED ensures that

Microsoft SQL Server 2005 8-3


Copyright © by Application Developers Training Company
All rights reserved. Reproduction is strictly prohibited.
Transactions and Error Handling

each transaction is either completed or rolled back so that data remains in a


consistent state in accordance with data integrity rules. In addition, it prevents
concurrent transactions from reading data or interfering with the transaction
until it is complete. Isolation levels are described in the Isolation Levels in the
Database Engine topic in SQL Server Books Online.

Transactions and Locking


Locks are held as long as the transaction is active. For explicit transactions,
this means until a COMMIT or ROLLBACK statement is issued. When data is
used in read-only operations such as a SELECT statement, shared locks are
placed on the data. Once the data is read, the lock is quickly released in sub-
second time. Row-level locking was introduced in SQL Server 7.0, and each
subsequent version of SQL Server has improved locking strategies.

SQL Server uses a dynamic locking strategy to determine the most cost-
effective locks by performing calculations that correct the granularity of
locking for your data operations. For instance, a SELECT statement that reads
all the rows in a table would expend more resources if it were to use shared
row locking rather than page-level or table-level locking. SQL Server will
perform the calculation behind the scenes and determine the most efficient
lock mode for any given operation. You can override this mechanism with lock
hints, but should avoid doing so without a good reason.

Viewing Lock Information


Several mechanisms are available for viewing locks in SQL Server 2005:

• EnumLocks in a SQL Server Management (SMO) application.


• The Locks event category in a SQL Server Profiler trace.
• The sys.dm_tran_locks procedure, which returns information about
currently active lock manager resources.
• The sp_lock procedure and sys.syslockinfo compatibility view, which
are included for backward compatibility.
• The Locks object in the System Monitor, a condensed view of which is
shown in Figure 1.

Figure 1. Viewing locks in the System Monitor.

8-4 Microsoft SQL Server 2005


Copyright © by Application Developers Training Company
All rights reserved. Reproduction is strictly prohibited.
Transaction Concepts

The Locking in the Database Engine topic in SQL Server Books Online
provides more detail about locking and monitoring locks.

Avoiding Blocked Transactions


Blocking happens when transactions are blocked by other transactions⎯the
transactions involved just sit and wait. On a network, blocked transactions will
either hang or eventually time out with an error message. To demonstrate
blocking, initiate a transaction but don’t commit or roll it back.

BEGIN TRAN
UPDATE dbo.Categories
SET CategoryName = 'Drinks'
WHERE CategoryID = 1;

Open a second connection and execute this SELECT statement. Note that the
wheels are spinning but no results are returned. Issue a ROLLBACK in the
first connection. The SELECT statement then executes in the second
connection, displaying the data.

Working around Deadlocks


Deadlocks are a possibility when too many locks are held for too long. A
deadlock occurs when two separate processes each hold a resource that the
other process needs. Each process waits to free the resource it is holding until
the other resource becomes available. Figure 2 shows Transaction1 attempting
to access a resource locked by Transaction2, and Transaction2 attempting to
access a resource locked by Transaction1. Unless one of the processes is
forced to yield, they will stay deadlocked forever. If SQL Server did not select
a deadlock victim, your server would eventually run out of available processes
and crash.

Figure 2. Diagram of a deadlock.

Microsoft SQL Server 2005 8-5


Copyright © by Application Developers Training Company
All rights reserved. Reproduction is strictly prohibited.
Transactions and Error Handling

SQL Server chooses as a deadlock victim the transaction that is least expensive
to roll back, generating error code 1205. You can test for this error and either
resubmit or cancel the query. You can also specify the priority of a session by
using the SET DEADLOCK_PRIORITY and choosing LOW, NORMAL, or
HIGH or by setting the priority to an integer value in the range of (-10 to 10).
The following statement sets it to LOW, making the session more likely to be a
deadlock victim.

SET DEADLOCK_PRIORITY LOW

Deadlock priority defaults to NORMAL. SQL Server chooses a random victim


when two sessions have the same deadlock priority and the same cost in rolling
back the transaction.

Deadlocks are difficult to simulate in a development environment; they seem


to appear only when your database is running, with many users attempting to
complete the same operation at the same time. The best way to prevent
blocking and deadlocks is to avoid creating situations that can cause them.
Here are several suggestions for avoiding blocking and deadlocks:

• Access objects in the same order. If both T1 and T2 shown in Figure 2


had accessed R1 and R2 in the same order, one process would have
gone into a wait queue while the other transaction completed
successfully.
• Avoid user interaction in transactions. Collect all necessary input from
users before initiating transactions. If you start a transaction, then ask
for user input, you’re setting yourself up for blocking issues.
• Keep transactions short and in one batch. The longer a transaction
holds resources, the more contention there will be for those resources.
• Use as low an isolation level as possible. A lower isolation level
translates into greater efficiency, as SQL Server uses fewer locking
resources to ensure data integrity.
• Avoid recursive and nested triggers. Triggers that fire other triggers
can cause a cascading transaction tree that lengthens the duration of a
transaction and blocks other processes.
• Don’t make coding errors. A BEGIN TRAN in an explicit transaction
without a COMMIT or ROLLBACK will lock resources indefinitely.

8-6 Microsoft SQL Server 2005


Copyright © by Application Developers Training Company
All rights reserved. Reproduction is strictly prohibited.
Applications and Transactions

Applications and Transactions


When creating a database application, your goal should be to “tread lightly”
upon the database server. It is important to keep transactions as short as
possible. The fewer resources you use from each client; the more clients the
server can support. In addition, the longer each transaction runs, the more
likely it will block other transactions.

Designing Transactional Support


There are two basic types of database applications, although many applications
combine both types:

• Online transaction processing (OLTP)


• Decision support (often referred to as OLAP)
OLTP applications are optimized for managing changes to data, and require a
high level of concurrency and atomicity. In OLTP systems with many users,
transactions must be as short as possible to reduce locking contention for
resources between concurrent connections.

Decision support (OLAP) applications are often denormalized to support data


queries that do not change data. The tables are heavily indexed, and the raw
data is frequently preprocessed and organized to support the various types of
queries used. Because the users are not changing data, concurrency and
atomicity are not a concern. However, if your application is a hybrid
application that combines both OLTP and OLAP, you need to weigh the
tradeoffs between optimizing for transactions against optimizing for queries.

Here are some additional guidelines for creating efficient transactional


applications:

• Access the least amount of data possible during a transaction. This


lessens the number of locked rows and reduces contention with other
transactions.
• Keep transactional boundaries on the server, not in client code. This
reduces round trips to the server and enhances concurrency.
• Validate data on the client before submitting it to the server. Do not
rely on the server to raise errors for bad data or invalid parameter
values. Use parameterized stored procedures that also validate input
and implement error handling.
• Keep the transaction as short as possible. Do not begin a transaction
until it is required. Once the transaction is open, execute the
modification statements and immediately commit or roll back.

Microsoft SQL Server 2005 8-7


Copyright © by Application Developers Training Company
All rights reserved. Reproduction is strictly prohibited.
Transactions and Error Handling

• Consider using the snapshot isolation level for read-only queries so


that less blocking occurs. The READ UNCOMMITTED isolation
level is also appropriate for long-running read-only queries that
aggregate large volumes of data.

Understanding Compile and Runtime


Errors
If an error occurs that prevents the successful completion of a transaction, SQL
Server automatically rolls back the transaction and frees all resources. If a
client connection is the cause of the failure, all pending transactions for that
connection are also rolled back. However, this behavior is not always as
straightforward as you might expect. Autocommit transactions in a batch
behave differently, depending on the type of errors involved.

If a runtime statement error (such as a constraint violation) occurs in a batch,


the default behavior is to roll back only the statement that generated the error.
The SET XACT_ABORT ON statement changes this behavior and causes an
automatic rollback. However, it has no effect on syntax errors.

Syntax and Compile Errors


When operating in Autocommit mode, the Database Engine will roll back a
batch of SQL statements that have a syntax error in only one line. A compile
error prevents the Database Engine from creating an execution plan, so nothing
in the batch is executed.

See Tranasctions In the following example, none of the INSERT statements are executed
ErrorHandling.SQL because of the compile error in the third INSERT statement. It appears that the
first two INSERT statements are rolled back, but in fact they never executed.

8-8 Microsoft SQL Server 2005


Copyright © by Application Developers Training Company
All rights reserved. Reproduction is strictly prohibited.
Applications and Transactions

-- Create the table


CREATE TABLE dbo.CompileErrors
(ID INT PRIMARY KEY,
ColValue CHAR(4));
GO

-- Create the batch


INSERT INTO dbo.CompileErrors VALUES (1, 'aaaa');
INSERT INTO dbo.CompileErrors VALUES (2, 'bbbb');
INSERT INTO dbo.CompileErrors VALUSE (3, 'cccc');
GO

-- Display the data


SELECT * FROM CompileErrors;
GO

The Messages pane displays the error and that no rows were returned by the
SELECT statement, as shown in Figure 3.

Figure 3. No rows are inserted from a batch if there is a compile error in one
statement.

However, if you execute each INSERT as a separate transaction, then each


statement is in its own isolated transaction and you receive a syntax error only
on the third INSERT. The SELECT statement displays two rows, as shown in
Figure 4.

Microsoft SQL Server 2005 8-9


Copyright © by Application Developers Training Company
All rights reserved. Reproduction is strictly prohibited.
Transactions and Error Handling

INSERT INTO dbo.CompileErrors VALUES (1, 'aaaa');


GO
INSERT INTO dbo.CompileErrors VALUES (2, 'bbbb');
GO
INSERT INTO dbo.CompileErrors VALUSE (3, 'cccc');
GO

Figure 4. Rows without syntax errors are inserted if they are not part of a batch
with a syntax error.

Runtime Errors
If you have a runtime error in one statement in a batch, other statements that
do not have errors will commit. This example batch adds new rows and
generates a duplicate primary key error on the third row. Figure 5 shows that
two rows from the batch were inserted.

INSERT INTO dbo.CompileErrors VALUES (11, 'aaaa');


INSERT INTO dbo.CompileErrors VALUES (12, 'bbbb');
INSERT INTO dbo.CompileErrors VALUES (11, 'cccc');

Figure 5. The results from inserting rows with a runtime error in one statement.

8-10 Microsoft SQL Server 2005


Copyright © by Application Developers Training Company
All rights reserved. Reproduction is strictly prohibited.
Applications and Transactions

Invalid Object Name Errors


Errors in a batch that contains invalid object names also behave in the same
way. The reason is that SQL Server uses deferred name resolution, so in the
following example, the name CompileErrrs isn’t resolved until runtime. Figure
6 displays the results.

INSERT INTO dbo.CompileErrors VALUES (111, 'aaaa');


INSERT INTO dbo.CompileErrors VALUES (112, 'bbbb');
INSERT INTO dbo.CompileErrrs VALUES (113, 'cccc');
GO

Figure 6. Rows around an invalid table name in a batch are also inserted.

Microsoft SQL Server 2005 8-11


Copyright © by Application Developers Training Company
All rights reserved. Reproduction is strictly prohibited.
Transactions and Error Handling

Creating Explicit Transactions


Explicit transactions wrap up all of the rows in a transaction or batch and
commit them as a single unit of work. If an error occurs on any row, all of the
rows are rolled back. Explicit transaction mode lasts only for the duration of
the transaction. When the transaction ends with a COMMIT or ROLLBACK
statement, the connection returns to the transaction mode it was in before the
explicit transaction began. All locks and resources are released.

Explicit Transaction Syntax


There are three basic parts to explicit transaction syntax:

• BEGIN TRANSACTION marks the starting point of an explicit


transaction for a connection.
• COMMIT TRANSACTION ends a transaction successfully if no
errors occurred. All data modifications made in the transaction become
a permanent part of the database. Resources held by the transaction are
freed.
• ROLLBACK TRANSACTION erases a transaction in which errors
are encountered. All data that the transaction modified returns to the
state it was in at the start of the transaction. Resources that the
transaction held are freed.

Nested Transactions
Transactions can be nested inside other transactions. This usually occurs when
a stored procedure, with its own transactions, executes another stored
procedure with its own transactions. SQL Server always gives precedence to
the outer transaction. However, if an error occurs at any level, all of the nested
transactions are rolled back. This behavior exists to protect your data. If any
part of a transaction was able to commit while another part was rolled back,
your data would be left in an inconsistent state.

Using @@TRANCOUNT
The @@TRANCOUNT function returns the number of active transactions for
the current connection. In this simple example, @@TRANCOUNT determines
whether a transaction is active and if so, rolls it back. The Messages pane
shown in Figure 7 seems misleading until you consider that the rows affected
message occurs before the PRINT statements. This indicates that no error
occurred that would cause the transaction to be rolled back. Executing a
SELECT statement on the Employees table shows the original value of
Davolio.

8-12 Microsoft SQL Server 2005


Copyright © by Application Developers Training Company
All rights reserved. Reproduction is strictly prohibited.
Creating Explicit Transactions

BEGIN TRANSACTION;
UPDATE dbo.Employees
SET LastName = 'Da Volio'
WHERE LastName = 'Davolio';
IF @@TRANCOUNT > 0
BEGIN
PRINT N'The transaction is active.';
ROLLBACK TRANSACTION;
PRINT N'The transaction has been rolled back.';
END
GO

Figure 7. Testing @@TRANCOUNT.

Transact-SQL Error Handling in


Transactions
This section covers Transact-SQL error handling in a transaction and how to
effectively communicate errors to a client application. Traditional error
handling in Transact-SQL is cumbersome, especially if you’re accustomed to
error handling in a modern programming language. However, SQL Server
2005 introduces try-catch error handling, which the next section covers. This
section explores the basic principles of error handling, which haven’t changed.

When it comes to error handling, the best offense is a good defense. Whatever
you can do to prevent runtime errors will simplify the process of handling
them when they do occur. Transactions and error handling are most effective
within stored procedures. So, to make your transactions more efficient and
secure, set default values for all input parameters, validate them, and exit the
stored procedure if the parameters don’t pass muster.

Microsoft SQL Server 2005 8-13


Copyright © by Application Developers Training Company
All rights reserved. Reproduction is strictly prohibited.
Transactions and Error Handling

Using @@ERROR in a Transaction


The @@ERROR function returns the error number for the last Transact-SQL
statement that executed. @@ERROR is cleared and reset on each statement
that executes; therefore, you need to check it immediately after the statement is
verified, or save it to a local variable.

@@ERROR messages are stored in the sys.messages catalog view, where


@@ERROR contains the value from the sys.messages.message_id column for
that error. You can view the text associated with an @@ERROR error number
in sys.messages by using the following query. Executing this query without a
WHERE clause returns 67,941 rows.

SELECT message_id, text from sys.messages

The following example creates a transaction with error handling. In this case,
the code attempts to insert a new record in the Customers table, which violates
the primary key constraint on CustomerID. The error value is captured in a
local variable, and a message is displayed.

DECLARE @err int


BEGIN TRANSACTION;
INSERT INTO dbo.Customers (CustomerID, CompanyName)
VALUES ('ALFKI', 'New ALFKI');
SET @Err = @@ERROR
IF @Err = 0
BEGIN
PRINT 'Commit transaction.';
COMMIT
END
ELSE
BEGIN
PRINT 'Error = ' + CAST(@Err AS varchar(10));
ROLLBACK
END
GO

8-14 Microsoft SQL Server 2005


Copyright © by Application Developers Training Company
All rights reserved. Reproduction is strictly prohibited.
Creating Explicit Transactions

Creating Stored Procedures to Manage


Transactions
The simple error handling shown previously is not sufficient for transactional
stored procedures in a client application. In order to create robust applications,
you need to implement transactions in stored procedures using the following
guidelines:

• Validate input parameters and business rules up front, which saves


time by not wasting cycles on the server with failed transactions.
• Anticipate errors and perform checks before opening the transaction.
Errors are expensive, so save them for actual runtime errors, not
validation.
• Use SET NO COUNT ON and return detailed error information to
client applications. Output parameters are a good choice because they
are more flexible than raising errors.
In addition to sending back error information to clients, it’s also nice to send
back general status information about the success/failure of an operation.
Every stored procedure that modifies data should return a success/failure code
and some kind of message. Standardizing a success/failure pattern simplifies
client coding, making it easier to determine the status of server operations and
branch accordingly. At a minimum, you should consider creating the following
two output parameters:

• An integer value indicating success or failure. For example, use 0 for


success (@@ERROR=0) and an error number for failure.
• A string with more detailed information. This additional information
can be used in many different ways; for example, in a dialog box or for
logging.
The following example creates a stored procedure that implements an explicit
transaction to insert a row into the Categories table. The stored procedure
performs the following actions:

• Declares an input parameter for @CategoryName.


• Declares three output parameters. @CategoryID returns the new
identity column value for the inserted row. @ReturnCode returns 0 on
success and an error number on failure. @ReturnMessage returns a
custom, context-specific message indicating the results of the
transaction.
• Uses SET NOCOUNT ON, which suppresses the done-in-proc
message. Some client APIs process this as a second result set, which
can have unintended consequences.
• Declares some working variables to capture @@ERROR,
@@ROWCOUNT, and SCOPE_IDENTITY values.

Microsoft SQL Server 2005 8-15


Copyright © by Application Developers Training Company
All rights reserved. Reproduction is strictly prohibited.
Transactions and Error Handling

• Tests whether the CategoryName is null. If it is, there’s no point in


proceeding any further.
• Tests whether the CategoryName already exists. In this particular case,
the test is necessary because this column has no unique index in the
database to prevent duplicate values. However, you want to perform
this test even if an index, constraint, or trigger exists that disallows
duplicates. This test is less expensive than attempting an insert that is
bound to fail anyway. The code returns if this test fails.
• Begins the transaction and performs the insert.
• Selects @@ERROR and @@ROWCOUNT into the local variables
for further processing. Note that the SELECT statement is necessary
here instead of SET because of the transitory nature of both functions.
• Tests whether the local @Err variable is non-zero. If it is, then the
@ReturnCode is set to the error number, the @ReturnMessage is set to
a custom string, the transaction is rolled back, and the RETURN
statement is issued.
• Tests the @Rows variable. The insert might have failed without
returning an error, although that is unlikely. If so, @ReturnCode is set
to the duplicate row number and the @ReturnMessage is set to ‘Insert
failed’ to indicate at which point an error was raised. The code issues
the RETURN statement.
• If the code gets this far, the transaction succeeded and the COMMIT is
issued. The SCOPE_IDENTITY function retrieves the new identity
column value, the @ReturnCode is set to 0, and the @ReturnMessage
is set to a string value indicating success.

8-16 Microsoft SQL Server 2005


Copyright © by Application Developers Training Company
All rights reserved. Reproduction is strictly prohibited.
Creating Explicit Transactions

CREATE PROCEDURE dbo.InsertCategoryTransaction


@CategoryName nvarchar(15) = NULL,
@CategoryID int = NULL OUTPUT,
@ReturnCode int = NULL OUTPUT,
@ReturnMessage nvarchar(255) = NULL OUTPUT
AS
SET NOCOUNT ON

-- Declare some working variables


DECLARE @Err int;
DECLARE @Rows int;
DECLARE @identity int;

-- Exit if CategoryName is null.


IF @CategoryName IS NULL
BEGIN
SELECT @ReturnCode = 515,
@ReturnMessage = 'Null CategoryName not allowed.'
RETURN
END

-- Exit if CategoryName already exists.


IF EXISTS (SELECT CategoryName FROM dbo.Categories
WHERE CategoryName=@CategoryName)
BEGIN
SELECT @ReturnCode = 2601,
@ReturnMessage = 'Name already exists.'
RETURN
END

-- Perform the transaction


BEGIN TRANSACTION
INSERT INTO dbo.Categories (CategoryName)
VALUES (@CategoryName);

-- Pick up @@ERROR and @@ROWCOUNT


SELECT @Err = @@ERROR, @Rows = @@ROWCOUNT

Microsoft SQL Server 2005 8-17


Copyright © by Application Developers Training Company
All rights reserved. Reproduction is strictly prohibited.
Transactions and Error Handling

-- If there's an error, rollback.


IF @Err <> 0
BEGIN
SELECT @ReturnCode=@Err,
@ReturnMessage='Error occurred.'
ROLLBACK
RETURN
END

-- If no rows inserted, rollback.


IF @Rows = 0
BEGIN
SELECT @ReturnCode=2601,
@ReturnMessage='Insert failed.'
ROLLBACK
RETURN
END

-- Success! Commit the transaction.


ELSE
BEGIN
COMMIT
SET @identity=SCOPE_IDENTITY();
SELECT @ReturnCode=0, @CategoryID=@identity,
@ReturnMessage='Transaction succeeded, row added.'
RETURN
END
GO

Executing the Stored Procedure


To test whether the transaction succeeded, you need to declare some variables
to supply the input parameter values and retrieve the values from the output
parameters. After executing the stored procedure, you can inspect the results
with a SELECT statement. The key is to test with invalid values as well as
valid values.

8-18 Microsoft SQL Server 2005


Copyright © by Application Developers Training Company
All rights reserved. Reproduction is strictly prohibited.
Creating Explicit Transactions

DECLARE @CategoryName nvarchar(15)


DECLARE @CategoryID int
DECLARE @ReturnCode int
DECLARE @ReturnMessage nvarchar(255)

SET @CategoryName = 'Seafood'

EXECUTE dbo.InsertCategoryTransaction
@CategoryName,
@CategoryID OUTPUT,
@ReturnCode OUTPUT,
@ReturnMessage OUTPUT;

SELECT @CategoryID AS CategoryId,


@ReturnCode AS ReturnCode,
@ReturnMessage AS ReturnMessage;
GO

If you test with an existing value as shown in the previous code, you should
see the results shown in Figure 8.

Figure 8. Results of a failed transaction.

Figure 9 displays the results when a transaction succeeds.

Figure 9. Results of a successful transaction.

The previous example works⎯after a fashion. It produces the desired result of


implementing an explicit transaction and returning information to the caller.
However, it involves writing an awful lot of Transact-SQL code and the
execution path is difficult to follow. It could also be written with a GOTO

Microsoft SQL Server 2005 8-19


Copyright © by Application Developers Training Company
All rights reserved. Reproduction is strictly prohibited.
Transactions and Error Handling

statement branching to an error handling block, which would simplify the


code, but in SQL Server 2005 a far better option exists⎯TRY/CATCH error
handling, which you’ll learn more about later in the chapter.

Using RAISERROR
RAISERROR is useful when you want to return an error message or
informational message to the caller. The syntax allows you to raise the error
with a message ID, string, or local variable. The severity and state arguments
are required; however, the state argument is an arbitrary value.

RAISERROR ( { msg_id | msg_str | @local_variable }


{ ,severity ,state }
[ ,argument [ ,...n ] ] )
[ WITH option [ ,...n ] ]

How RAISERROR behaves depends on the severity level of the error. Severity
levels of 1 to 10 are considered informational messages, not errors. Severity
levels of 11 to 19 are considered errors. Severity levels from 19 to 25 indicate
fatal errors and are required to be logged. For complete information about error
severity levels, see Database Engine Error Severities in SQL Server Books
Online.

You can use RAISERROR with a user-defined message stored in


sys.messages, or you can build a message dynamically. This example
demonstrates how to raise a dynamic error when a duplicate CategoryName is
found, as shown in Figure 10:

IF EXISTS (SELECT CategoryName FROM dbo.Categories


WHERE CategoryName='Seafood')
BEGIN
RAISERROR ('Duplicate name detected.', 16, 1);
END
GO

Figure 10. The results from using RAISERROR.

8-20 Microsoft SQL Server 2005


Copyright © by Application Developers Training Company
All rights reserved. Reproduction is strictly prohibited.
Creating Explicit Transactions

Creating User-Defined Errors


You can also use RAISERROR to return user-defined error messages. The
following example shows a user-defined error message that uses the
sp_addmessage system stored procedure. The required arguments are
@msgnum, which is a number greater than 50000, @severity, which is a
number between 1 and 25, and @msgtext, which is a string that you define.
The additional arguments specify the language, whether the error should be
logged, and whether the error should replace an existing error with the same
number.

sp_addmessage
[@msgnum=] msg_id,
[@severity=] severity,
[@msgtext=] 'msg'
[,[ @lang = ] 'language']
[,[ @with_log=] 'with_log']
[,[ @replace=] 'replace']

The following example creates a custom error message with a severity level of
15 that returns an error message with the session ID and name of the database
in which the error occurred as substitution string placeholders. To raise the
error, you need to use @@SPID and DB_NAME() to retrieve those values:

EXECUTE sp_addmessage 50003, 16,


N'Session ID %d caused an error in %s.';
GO

-- Raise the error:


DECLARE @spid INT;
SET @spid = @@SPID;
DECLARE @name NVARCHAR(128);
SET @name = DB_NAME();

RAISERROR (50003, 10, 1, @spid, @name)


GO

Microsoft SQL Server 2005 8-21


Copyright © by Application Developers Training Company
All rights reserved. Reproduction is strictly prohibited.
Transactions and Error Handling

Using TRY/CATCH Error Handling


TRY/CATCH error handling is one of the major new improvements in SQL
Server 2005, overcoming many of the limitations of error handling in earlier
versions of SQL Server. All errors with a severity greater than 10 are
trappable, except for errors that terminate a connection.

TRY/CATCH Overview
TRY/CATCH error handling works much the same way in SQL Server as it
does in a programming language. You place a statement in a BEGIN TRY
block followed by a BEGIN CATCH block. If the statement generates an
error, the statements in the BEGIN CATCH block execute until the END
CATCH is reached. The END TRY is skipped. If no error occurs, the CATCH
block is skipped entirely and processing continues to the END TRY block.

This example demonstrates a transaction that attempts to insert a duplicate


primary key value into the Customers table. The BEGIN TRY wraps the
transaction. If the insert succeeds, the transaction is committed and the PRINT
statement executed. If an error occurs, the transaction is rolled back in the
CATCH block and the message shown in Figure 11 is displayed.

BEGIN TRY
BEGIN TRANSACTION;
INSERT INTO dbo.Customers (CustomerID, CompanyName)
VALUES ('ALFKI', 'New ALFKI');
COMMIT
PRINT 'Transaction committed.';
END TRY

BEGIN CATCH
ROLLBACK
PRINT 'Transaction rolled back.';
END CATCH

Figure 11. Rolling back a transaction.

8-22 Microsoft SQL Server 2005


Copyright © by Application Developers Training Company
All rights reserved. Reproduction is strictly prohibited.
Using TRY/CATCH Error Handling

Error Chaining
If you generate an error that is not within a TRY/CATCH block, that error is
passed back up the call stack to the caller. For example, Sproc1 calls Sproc2
from inside a TRY/CATCH block. Sproc2 does not have a TRY/CATCH
block and generates an error. That error is passed back up the stack to Sproc1
and is processed in Sproc1’s CATCH block. If there is no TRY/CATCH block,
the error is passed to the client.

All errors are handled in the CATCH block and are not returned to the caller.
When the code in the CATCH block completes, control passes to the statement
immediately after the END CATCH statement. If you need to pass error
information to the client, you can do so using other means.

Errors that a TRY/CATCH does not handle include:

• Warnings or informational messages with a severity of 10 or lower.


• Errors with severity of 20 or higher that terminate the connection.
• Any broken connection, including those terminated with a KILL
statement.
• Syntax and compile errors.
• Recompilation errors, such as object name resolution failures.

Error Handling Functions


One of the benefits of TRY/CATCH error handling is that you can use new
functions in the CATCH block to return detailed information about the error
that occurred. These functions can be used from anywhere inside the CATCH
block, but return NULL if called from outside the scope of the CATCH block:

• ERROR_NUMBER() returns the number of the error.


• ERROR_SEVERITY() returns the severity level of the error.
• ERROR_STATE() returns the error state number.
• ERROR_PROCEDURE() returns the name of the stored procedure
or trigger where the error occurred.
• ERROR_LINE() returns the line number inside the routine that
caused the error.
• ERROR_MESSAGE() returns the complete text of the error message.
The text includes the values supplied for any substitutable parameters,
such as lengths, object names, or times.

Microsoft SQL Server 2005 8-23


Copyright © by Application Developers Training Company
All rights reserved. Reproduction is strictly prohibited.
Transactions and Error Handling

This is what the previous example looks like when it is expanded to include all
of the error functions in the CATCH block. The results are shown in Figure 12.

BEGIN TRY
BEGIN TRANSACTION;
INSERT INTO dbo.Customers (CustomerID, CompanyName)
VALUES ('ALFKI', 'New ALFKI');
COMMIT
PRINT 'Transaction committed.';
END TRY

BEGIN CATCH
ROLLBACK
SELECT
ERROR_NUMBER() AS Number,
ERROR_SEVERITY() AS Severity,
ERROR_STATE() AS State,
ERROR_PROCEDURE() AS procedureName,
ERROR_LINE() AS Line,
ERROR_MESSAGE() AS messageText;
PRINT 'Transaction rolled back.';
END CATCH

Figure 12. Using the new error handling functions to display information.

Using RAISERROR with TRY/CATCH


You can catch RAISERROR statements in a TRY/CATCH block when the
severity level is greater than 10 and does not terminate the connection. Errors
with a severity level between 20 and 25 are not handled in the CATCH block
because execution is usually aborted. Errors with severity from 0 through 10
are informational messages and do not cause execution to jump from the
CATCH block. This example demonstrates two RAISERROR messages, one
with a severity of 9 and one with a severity of 16. When the code executes,
only the error with the severity of 16 is handled in the CATCH block. The
error with the severity of 9 is handled inline, as shown in Figure 13.

8-24 Microsoft SQL Server 2005


Copyright © by Application Developers Training Company
All rights reserved. Reproduction is strictly prohibited.
Using TRY/CATCH Error Handling

BEGIN TRY
RAISERROR ('Error severity 9', 9, 1);
RAISERROR ('Error severity 16', 16, 1);
END TRY

BEGIN CATCH
DECLARE @ErrorMessage NVARCHAR(4000);
DECLARE @ErrorSeverity INT;

SELECT
@ErrorMessage = ('In CATCH block: ' +
ERROR_MESSAGE()),
@ErrorSeverity = ERROR_SEVERITY();
RAISERROR (@ErrorMessage,
@ErrorSeverity, 1);
END CATCH;
GO

Figure 13. Displaying informational and error messages.

Using TRY/CATCH in a Stored


Procedure
The next example demonstrates how to use TRY/CATCH error handling to
replace @@ERROR error handling. This version of the stored procedure is
quite an improvement over the previous version, with fewer lines of code and a
clear execution path. It differs in the following respects:

• No working variables are needed to capture volatile error and row


count information.

Microsoft SQL Server 2005 8-25


Copyright © by Application Developers Training Company
All rights reserved. Reproduction is strictly prohibited.
Transactions and Error Handling

• The BEGIN TRY statement is immediately after SET NO COUNT


ON so that any error in the following code will jump to the CATCH
block.
• Parameter validation uses RAISERROR to jump to the catch block,
eliminating the extra steps of setting the output parameter values and
executing the RETURN statement.
• The COMMIT statement occurs immediately after the INSERT
statement and the output parameter values are set here if the INSERT
succeeds. You don’t need to test for @@ERROR or
@@ROWCOUNT because the COMMIT will throw if the transaction
fails at this point. If the failure is caused by termination of the
connection, the transaction will be automatically rolled back.
• The ROLLBACK is the first statement in the CATCH block. The
@ReturnCode is set to ERROR_NUMBER() and the other error
functions are concatenated into a single string to be passed to the client
in the @ReturnMessage output parameter. The error number will be
50000 for the RAISERROR statements generated from parameter
validation.

CREATE PROCEDURE dbo.InsertCategoryTryCatch


@CategoryName nvarchar(15) = NULL,
@CategoryID int = NULL OUTPUT,
@ReturnCode int = NULL OUTPUT,
@ReturnMessage nvarchar(255) = NULL OUTPUT
AS
SET NOCOUNT ON

BEGIN TRY
-- Test if CategoryName null.
IF @CategoryName IS NULL
RAISERROR ('Validation failed: Null CategoryName.',
16, 1);

-- Test if CategoryName already exists.


IF EXISTS (SELECT CategoryName FROM dbo.Categories
WHERE CategoryName=@CategoryName)
RAISERROR ('Validation failed: Duplicate
CategoryName.', 16, 1);

-- Begin the transaction.


BEGIN TRANSACTION

8-26 Microsoft SQL Server 2005


Copyright © by Application Developers Training Company
All rights reserved. Reproduction is strictly prohibited.
Using TRY/CATCH Error Handling

INSERT INTO dbo.Categories (CategoryName)


VALUES (@CategoryName);
COMMIT
SET @CategoryID=SCOPE_IDENTITY();
SELECT @ReturnCode=0,
@ReturnMessage='Success! ' + @CategoryName + '
added.';
END TRY

BEGIN CATCH
-- Test to see if we're in a transaction.
IF @@TRANCOUNT > 0
ROLLBACK

-- Return error information to client.


SELECT @ReturnCode = ERROR_NUMBER();
SELECT @ReturnMessage = ERROR_MESSAGE() +
' Severity=' + CAST(ERROR_SEVERITY() AS nvarchar(2)) +
'; State=' + CAST(ERROR_STATE() AS nvarchar(2)) +
'; Proc=' + CAST(ERROR_PROCEDURE() AS nvarchar(50)) +
'; Line=' + CAST(ERROR_LINE() AS nvarchar(10));
END CATCH
GO

The only difference in executing the TRY/CATCH stored procedure is the


name of the stored procedure. The results are shown in Figure 14.

Microsoft SQL Server 2005 8-27


Copyright © by Application Developers Training Company
All rights reserved. Reproduction is strictly prohibited.
Transactions and Error Handling

DECLARE @CategoryName nvarchar(15)


DECLARE @CategoryID int
DECLARE @ReturnCode int
DECLARE @ReturnMessage nvarchar(255)

SET @CategoryName = 'Seafood'

EXECUTE dbo.InsertCategoryTryCatch
@CategoryName,
@CategoryID OUTPUT,
@ReturnCode OUTPUT,
@ReturnMessage OUTPUT;

SELECT @CategoryID AS CategoryId,


@ReturnCode AS ReturnCode,
@ReturnMessage AS ReturnMessage;
GO

Figure 14. Triggering an error with TRY/CATCH error handling.

Handling Uncommittable Transactions


with XACT_STATE
SQL Server 2005 adds a new transaction state called failed, also known as
doomed. Earlier versions of SQL Server supported only two transaction states:
active/committable and no open transaction. In SQL Server 2005, an explicit
transaction is in a failed state when an error occurs inside a TRY block and the
transaction has not yet been rolled back. The transaction is uncommittable, or
doomed, but the transaction continues to hold locks. This is useful for
scenarios when you’d like to investigate the cause of the error. Although you
can’t commit the transaction⎯all you can do is roll it back⎯you can issue
SELECT queries on the resources involved before you issue the ROLLBACK
statement.

8-28 Microsoft SQL Server 2005


Copyright © by Application Developers Training Company
All rights reserved. Reproduction is strictly prohibited.
Using TRY/CATCH Error Handling

Using the XACT_STATE function in a CATCH block enables you to


determine the state of the current transaction. XACT_STATE returns one of
three values:

1 The session has a committable transaction.

0 There is no active transaction (@@TRANCOUNT=0)

-1 The transaction is active, but uncommittable. The session can only


perform read operations until it rolls back the transaction.

You are most likely to encounter this state when the severity level is 17 or
higher, but you can simulate it by setting SET XACT_ABORT ON, which you
can use to force any transaction to enter an uncommittable state.

The following example demonstrates how to use XACT_STATE in the


CATCH block to determine whether the transaction is committable. The code
performs the following actions:

• Uses SET XACT_ABORT ON to force a constraint violation error to


fail the transaction.
• Attempts to delete the first row from the Categories table, triggering
an error.
• Tests whether XACT_STATE = 1 and performs a SELECT to return
the CategoryName. Note that only read operations are available until
the transaction is rolled back.
• Rolls back the transaction. The message is displayed in Figure 15.

Microsoft SQL Server 2005 8-29


Copyright © by Application Developers Training Company
All rights reserved. Reproduction is strictly prohibited.
Transactions and Error Handling

SET XACT_ABORT ON;


BEGIN TRY
BEGIN TRANSACTION;
-- Generate a constraint violation error.
DELETE FROM dbo.Categories WHERE CategoryID=1;
COMMIT TRANSACTION;
PRINT 'Transaction Committed.'
END TRY

BEGIN CATCH
IF (XACT_STATE()) = -1
BEGIN
DECLARE @category nvarchar(50)
SELECT @Category =
(SELECT CategoryName FROM dbo.Categories WHERE
CategoryID=1)
ROLLBACK
PRINT 'The ' + @category + ' category cannot be
deleted.';
END
END CATCH
GO

Figure 15. After testing XACT_STATE.

8-30 Microsoft SQL Server 2005


Copyright © by Application Developers Training Company
All rights reserved. Reproduction is strictly prohibited.
Using TRY/CATCH Error Handling

Summary
• A transaction is a series of SQL statements that must either all succeed
or all fail.
• SQL Server runs all implicit transactions in Autocommit mode by
default.
• You can implement explicit transactions with BEGIN
TRANSACTION, COMMIT, and ROLLBACK statements.
• Use transactions, isolation levels, and lock hints wisely to avoid
blocking and deadlocks.
• Syntax errors cause all statements in a batch to be rolled back in
Autocommit transactions.
• Runtime errors and invalid object name errors in a batch do not
prevent other statements in the batch from being committed.
• @@TRANCOUNT returns the number of active transactions.
• Output parameters in a stored procedure provide a good way to return
error information.
• Use TRY/CATCH error handling with errors that have a severity level
greater than 10 and that do not terminate the connection.
• SQL Server 2005 introduces a rich set of error handling functions to
return information from inside a CATCH block.
• Use RAISERROR to return a user-defined error.
• Use XACT_STATE to handle uncommittable transactions.

Microsoft SQL Server 2005 8-31


Copyright © by Application Developers Training Company
All rights reserved. Reproduction is strictly prohibited.
Transactions and Error Handling

(Review questions and answers on the following pages.)

8-32 Microsoft SQL Server 2005


Copyright © by Application Developers Training Company
All rights reserved. Reproduction is strictly prohibited.
Using TRY/CATCH Error Handling

Questions
1. What are the four parts of the ACID test that SQL Server transactions
ensure?

2. Which three statements are necessary to create an explicit transaction?

3. Which function returns the number of active transactions?

4. In Autocommit mode, which two types of errors do not prevent other


statements in a batch from committing?

5. Which function can you use in a CATCH block to return the name of the
stored procedure or function in which the error occurred?

6. What does the XACT_STATE function return when a transaction is active


but uncommittable?

Microsoft SQL Server 2005 8-33


Copyright © by Application Developers Training Company
All rights reserved. Reproduction is strictly prohibited.
Transactions and Error Handling

Answers
1. What are the four parts of the ACID test that SQL Server transactions
ensure?
Atomicity, consistency, isolation, and durability.

2. Which three statements are necessary to create an explicit transaction?


BEGIN TRANSACTION, COMMIT, and ROLLBACK.

3. Which function returns the number of active transactions?


@@TRANCOUNT

4. In Autocommit mode, which two types of errors do not prevent other


statements in a batch from committing?
Runtime errors and invalid object name errors.

5. Which function can you use in a CATCH block to return the name of the
stored procedure or function in which the error occurred?
ERROR_PROCEDURE()

6. What does the XACT_STATE function return when a transaction is active


but uncommittable?
-1

8-34 Microsoft SQL Server 2005


Copyright © by Application Developers Training Company
All rights reserved. Reproduction is strictly prohibited.
Lab 8:
Transactions and Error Handling

Lab 8:
Transactions and
Error Handling

Microsoft SQL Server 2005 8-35


Copyright © by Application Developers Training Company
All rights reserved. Reproduction is strictly prohibited.
Lab 8:
Transactions and Error Handling

Lab 8 Overview
In this lab you’ll learn to create explicit transactions and to implement
TRY/CATCH error handling.

To complete this lab, you’ll need to work through two exercises:

• Create a Transaction in a Stored Procedure


• Use TRY/CATCH Error Handling
Each exercise includes an “Objective” section that describes the purpose of the
exercise. You are encouraged to try to complete the exercise from the
information given in the Objective section. If you require more information to
complete the exercise, the Objective section is followed by detailed step-by-
step instructions.

8-36 Microsoft SQL Server 2005


Copyright © by Application Developers Training Company
All rights reserved. Reproduction is strictly prohibited.
Create a Transaction in a Stored Procedure

Create a Transaction in a Stored


Procedure

Objective
The objective of this section is to create an explicit transaction in a stored
procedure to add a new customer to the dbo.Customers table in Northwind.
You’ll create input parameters for the CustomerID and CompanyName values
and an output parameter to send back message information. You’ll create a
variable to test whether an error occurred. You’ll commit the transaction if
there are no errors, and roll it back if there are. You’ll execute the stored
procedure by supplying the values ‘ALFKI’ and Al’s Ale House and display
the message contained in the output parameter.

Things to Consider
• How do you create a stored procedure?
• How do you declare input and output parameters?
• How do you implement an explicit transaction?
• How do you test for errors?
• How do you commit/roll back the transaction?
• How do you execute the stored procedure?

Step-by-Step Instructions
1. Open a new query window and connect to the Northwind database.

USE Northwind;
GO

2. Create a stored procedure named AddCustomerLab1 with the following


input and output parameters.

Microsoft SQL Server 2005 8-37


Copyright © by Application Developers Training Company
All rights reserved. Reproduction is strictly prohibited.
Lab 8:
Transactions and Error Handling

CREATE PROCEDURE dbo.AddCustomerLab1


@CustomerID nchar(5) = NULL,
@CompanyName nvarchar(40) = NULL,
@ReturnMessage nvarchar(255) = NULL OUTPUT
AS

3. Use the SET NO COUNT ON statement and declare a variable to contain


the error.

SET NOCOUNT ON
DECLARE @err int;

4. Begin the transaction and test whether there are any errors.

BEGIN TRANSACTION
INSERT INTO dbo.Customers (CustomerID, CompanyName)
VALUES (@CustomerID, @CompanyName);
SELECT @err = @@ERROR

5. If there are no errors, commit the transaction.

IF @err = 0
BEGIN
COMMIT
SET @ReturnMessage='Transaction succeeded.';
END

6. Roll back the transaction if there are errors.

ELSE
BEGIN
ROLLBACK
SET @ReturnMessage='Transaction failed.';
END

8-38 Microsoft SQL Server 2005


Copyright © by Application Developers Training Company
All rights reserved. Reproduction is strictly prohibited.
Create a Transaction in a Stored Procedure

7. Create variables to use when executing the stored procedure.

ELSE
BEGIN
ROLLBACK
SET @ReturnMessage='Transaction failed.';
END

8. Supply the values for the input parameters.

SET @CompanyID = 'ALFKI'


SET @CompanyName = 'Alfred''s Ale House'

9. Execute the stored procedure and display the return message.

EXECUTE dbo.AddCustomerLab1
@CompanyID,
@CompanyName,
@ReturnMessage OUTPUT;

SELECT @ReturnMessage AS ReturnMessage;

Microsoft SQL Server 2005 8-39


Copyright © by Application Developers Training Company
All rights reserved. Reproduction is strictly prohibited.
Lab 8:
Transactions and Error Handling

Use TRY/CATCH Error Handling

Objective
In this exercise, you’ll add TRY/CATCH error handling to the stored
procedure you created in the first exercise. You’ll use the
ERROR_MESSAGE() function to return an error message in the output
parameter.

Things to Consider
• How do you implement TRY/CATCH error handling?
• How do you commit/roll back the transaction?
• How do you return a message in an output parameter from a built-in
function?

Step-by-Step Instructions
1. Create a new procedure named AddCustomerLab2 and declare the same
parameters you used in the first exercise.

CREATE PROCEDURE dbo.AddCustomerLab2


@CustomerID nchar(5) = NULL,
@CompanyName nvarchar(40) = NULL,
@ReturnMessage nvarchar(255) = NULL OUTPUT
AS
SET NOCOUNT ON

2. Create the BEGIN TRY block with the INSERT statement and commit the
transaction.

8-40 Microsoft SQL Server 2005


Copyright © by Application Developers Training Company
All rights reserved. Reproduction is strictly prohibited.
Use TRY/CATCH Error Handling

BEGIN TRY
BEGIN TRANSACTION
INSERT INTO dbo.Customers (CustomerID, CompanyName)
VALUES (@CustomerID, @CompanyName);
COMMIT
SET @ReturnMessage='Transaction succeeded.';
END TRY

3. Create the CATCH block to roll back the transaction. Set the output
parameter to the results of the ERROR_MESSAGE() function.

BEGIN CATCH
ROLLBACK
SET @ReturnMessage = ERROR_MESSAGE();
END CATCH

4. To execute the stored procedure, use the same commands that you did in
the first exercise. Change the name of the stored procedure, as shown in
bold. The output parameter message will be displayed in the results pane.

DECLARE @CompanyID nchar(5);


DECLARE @CompanyName nvarchar(40);
DECLARE @ReturnMessage nvarchar(255)

SET @CompanyID = 'ALFKI'


SET @CompanyName = 'Alfred''s Ale House'
EXECUTE dbo.AddCustomerLab2
@CompanyID,
@CompanyName,
@ReturnMessage OUTPUT;

SELECT @ReturnMessage AS ReturnMessage;


GO

Microsoft SQL Server 2005 8-41


Copyright © by Application Developers Training Company
All rights reserved. Reproduction is strictly prohibited.
Lab 8:
Transactions and Error Handling

8-42 Microsoft SQL Server 2005


Copyright © by Application Developers Training Company
All rights reserved. Reproduction is strictly prohibited.

You might also like