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

Microsoft SQL Server 2008 R2 Unleashed- P108 pot

10 143 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 223,25 KB

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

Nội dung

Triggers and Transaction Nesting To demonstrate the relationship between a trigger and the transaction nesting level, you can use the following SQL code to create a trigger on the employ

Trang 1

IF (@@error <> 0)

BEGIN

ROLLBACK TRAN mytran

RETURN –1969

END

/* Once you reach the end of the code, you need to pair the BEGIN TRAN,

if you issued it, with a COMMIT TRAN If you executed the SAVE TRAN

instead, you have nothing else to do end of game! */

IF (@trancount = 0)

COMMIT TRAN

RETURN 0

If you apply these concepts to all stored procedures that need to incorporate transaction

processing as well as the code that calls the stored procedures, you should be able to avoid

problems with transaction nesting and inconsistency in your transaction processing You

just need to be sure to check the return value of the stored procedure and determine

whether the whole batch should be failed or whether that one call is of little importance

to the overall outcome and the transaction can continue

For additional examples of and discussion about coding guidelines for stored procedures in

transactions, see Chapter 44, “Advanced Stored Procedure Programming and Optimization.”

Transactions and Triggers

SQL Server 2008 provides two types of Data Manipulation Language (DML) triggers: AFTER

and INSTEAD OF INSTEAD OF triggers perform their actions before any modifications are

made to the actual table the trigger is defined on

Whenever a trigger is invoked, it is always invoked within another transaction, whether

it’s a single-statement AutoCommit transaction or a user-defined multistatement

transac-tion This is true for both AFTER triggers and INSTEAD OF triggers Even though an INSTEAD

OF trigger fires before, or “instead of,” the data modification statement itself, if a

transac-tion is not already active, an AutoCommit transactransac-tion is still automatically initiated as the

data modification statement is invoked and prior to the invocation of the INSTEAD OF

trigger (For more information on AFTER and INSTEAD OF triggers, see Chapter 30,

“Creating and Managing Triggers.”)

NOTE

Although the information presented in this section applies to both AFTER and INSTEAD

OF triggers, the examples presented pertain primarily to AFTER triggers

Because the trigger is already operating within the context of a transaction, the only

trans-action control statements you should ever consider using in a trigger are ROLLBACK and

Trang 2

SAVE TRAN You don’t need to issue a BEGIN TRAN because a transaction is already active; a

BEGIN TRAN would only serve to increase the transaction nesting level, and that would

complicate things further

Triggers and Transaction Nesting

To demonstrate the relationship between a trigger and the transaction nesting level, you

can use the following SQL code to create a trigger on the employee table:

use bigpubs2008

go

CREATE TRIGGER tD_employee ON employee

FOR DELETE

AS

DECLARE @msg VARCHAR(255)

SELECT @msg = ‘Trancount in trigger = ‘ + CONVERT(VARCHAR(2), @@trancount)

PRINT @msg

RETURN

go

The purpose of this trigger is simply to show the state of the @@trancount within the

trigger as the deletion is taking place

If you now execute code for implied and explicit transactions, you can see the values of

@@trancount and behavior of the batch First, here’s the implied transaction:

set nocount on

print ‘Trancount before delete = ‘ + CONVERT(VARCHAR(2), @@trancount)

DELETE FROM employee WHERE emp_id = ‘PMA42628M’

print ‘Trancount after delete = ‘ + CONVERT( VARCHAR(2), @@trancount)

go

The results of this are as follows:

Trancount before delete = 0

Trancount in trigger = 1

Trancount after delete = 0

Because no transaction starts until the DELETE statement executes, the first value of

@@trancount indicates this with a value of 0 Within the trigger, the transaction count has

a value of 1; you are now inside the implied transaction caused by the DELETE After the

trigger returns, the DELETE is automatically committed, the transaction is finished, and

@@trancount returns to 0 to indicate that no transaction is currently active

Now explore what happens within an explicit transaction:

Trang 3

begin tran

print ‘Trancount before delete = ‘ + CONVERT(VARCHAR(2), @@trancount)

DELETE FROM employee WHERE emp_id = ‘PMA42628M’

print ‘Trancount after delete = ‘ + CONVERT( VARCHAR(2), @@trancount)

commit tran

print ‘Trancount after commit = ‘ + CONVERT( VARCHAR(2), @@trancount)

go

This code gives the following results:

Trancount before delete = 1

Trancount in trigger = 1

Trancount after delete = 1

Trancount after commit = 0

In this example, a transaction is already active when the DELETE is executed The BEGIN

TRAN statement initiates the transaction, and @@trancount is 1 before the DELETE is

executed The trigger becomes a part of that transaction, which is not committed until the

COMMIT TRAN statement is executed

What would happen, however, if the trigger performed a rollback? You can find out by

modifying the trigger to perform a rollback as follows:

ALTER TRIGGER tD_employee ON employee

FOR DELETE

AS

print ‘Trancount in trigger = ‘ + CONVERT(VARCHAR(2), @@trancount)

ROLLBACK TRAN

return

Now rerun the previous batch The outcome this time is as follows:

Trancount before delete = 1

Trancount in trigger = 1

Msg 3609, Level 16, State 1, Line 3

The transaction ended in the trigger The batch has been aborted

Notice in this example that the batch did not complete, as evidenced by the missing output

from the last two print statements When a rollback occurs within a trigger, SQL Server

aborts the current transaction, continues processing the commands in the trigger, and after

the trigger returns, aborts the rest of the batch and returns error message 3609 to indicate

that the batch has been aborted because the transaction ended within the trigger A

ROLLBACK TRAN statement in a trigger rolls back all work to the first BEGIN TRAN statement It

is not possible to roll back to a specific named transaction, although you can roll back to a

named savepoint, as discussed later in this section

Trang 4

Again, the batch and transaction are aborted when the trigger rolls back; any subsequent

statements in the batch are not executed The key concept to remember is that the trigger

becomes an integral part of the statement that fired it and of the transaction in which

that statement occurs

It is important to note, however, that although the batch is aborted immediately after

the trigger that performed a rollback returns, any statements within the trigger that

follow the ROLLBACK TRAN statement but before it returns are executed For example, you

can modify the previous trigger further to include a print statement after the ROLLBACK

TRAN statement:

ALTER TRIGGER tD_employee ON employee

FOR DELETE

AS

print ‘Trancount in trigger = ‘ + CONVERT(VARCHAR(2), @@trancount)

ROLLBACK TRAN

print ‘Trancount in trigger after rollback = ‘ + CONVERT(VARCHAR(2), @@trancount)

return

Now, if you rerun the previous batch, you can see the print statement after the ROLLBACK

TRAN but before the RETURN statement is executed:

Trancount before delete = 1

Trancount in trigger = 1

Trancount in trigger after rollback = 0

Msg 3609, Level 16, State 1, Line 3

The transaction ended in the trigger The batch has been aborted

Notice that the Trancount after the ROLLBACK TRAN in the trigger is now 0 If the trigger

subsequently performed any data modifications following the ROLLBACK TRAN, they would

now be running as AutoCommit transactions For this reason, you must be sure to issue a

RETURN statement to exit the trigger after a ROLLBACK TRAN is issued to avoid the trigger

performing any operations that would then be automatically committing, leaving no

opportunity to roll them back

Triggers and Multistatement Transactions

Now let’s look at another example First, you need to create a trigger to enforce referential

integrity between the titles table and publishers table:

The first statement is used to disable any previously created

DDL triggers in the database which would prevent creating a new trigger

Trang 5

DISABLE TRIGGER ALL ON titles

go

create trigger tr_titles_i on titles for insert as

declare @rows int — create variable to hold @@rowcount

select @rows = @@rowcount

if @rows = 0 return

if update(pub_id) and (select count(*)

from inserted i, publishers p

where p.pub_id = i.pub_id ) != @rows

begin

rollback transaction

raiserror (‘Invalid pub_id inserted’, 16, 1)

end

return

go

Next, for the trigger to take care of the referential integrity, you might first need to disable

the foreign key constraint on the titles table with a command similar to the following:

alter table titles nocheck constraint FK titles pub_id 0F424F67

NOTE

The system-generated name for the foreign key constraint may possibly be different on

your database You can use sp_helpconstraint titles to verify the name of the

for-eign key constraint on the pub_id column of the titles table and use it in place of

the constraint name specified in this example

Now, run a multistatement transaction with an invalid pub_id in the second insert statement:

/* transaction inserts rows into a table */

begin tran add_titles

insert titles (title_id, pub_id, title)

values (‘XX1234’, ‘0736’, ‘Tuning SQL Server’)

insert titles (title_id, pub_id, title)

values (‘XX1235’, ‘abcd’, ‘Tuning SQL Server’)

insert titles (title_id, pub_id, title)

values (‘XX1236’, ‘0877’, ‘Tuning SQL Server’)

commit tran

go

Msg 50000, Level 16, State 1, Procedure tr_titles_i, Line 10

Invalid pub_id inserted

Msg 3609, Level 16, State 1, Line 4

The transaction ended in the trigger The batch has been aborted

Trang 6

How many rows are inserted if ’abcd’ is an invalid pub_id? In this example, no rows are

inserted because the ROLLBACK TRAN in the trigger rolls back all modifications made by the

trigger, including the insert with the bad pub_id and all statements preceding it within

the transaction After the RETURN statement is encountered in the trigger, the rest of the

batch is aborted

CAUTION

You should never issue a BEGIN TRAN statement in a trigger because a transaction is

already active at the time the trigger is executed Rolling back to a named transaction

in a trigger is illegal and generates a runtime error, rolling back the transaction and

immediately terminating processing of the trigger and batch The only transaction

con-trol statements you should ever consider including in a trigger are ROLLBACK TRAN and

SAVE TRAN

Using Savepoints in Triggers

Although BEGIN TRAN statements are not recommended within a trigger, you can set a

savepoint in a trigger and roll back to the savepoint This technique rolls back only the

operations within the trigger subsequent to the savepoint The trigger and transaction it is

a part of are still active until the transaction is subsequently committed or rolled back

The batch continues processing

Savepoints can be used to avoid a trigger’s arbitrarily rolling back an entire transaction

You can roll back to the named savepoint in the trigger and then issue a raiserror and

return immediately to pass the error code back to the calling process The calling process

can then check the error status of the data modification statement and take appropriate

action, either rolling back the transaction, rolling back to a savepoint in the transaction,

or ignoring the error and committing the data modification

The following example shows a trigger that uses a savepoint:

alter trigger tr_titles_i on titles for insert as

declare @rows int — create variable to hold @@rowcount

select @rows = @@rowcount

if @rows = 0 return

save tran titlestrig

if update(pub_id) and (select count(*)

from inserted i, publishers p

where p.pub_id = i.pub_id ) != @rows

begin

rollback transaction titlestrig

raiserror (‘Invalid pub_id inserted’, 16, 1)

end

return

Trang 7

This trigger rolls back all work since the savepoint and returns an error number of 50000

In the transaction, you can check for the error number and make the decision about

whether to continue the transaction, roll back the transaction, or, if savepoints were set in

the transaction, roll back to a savepoint and let the transaction continue The following

example rolls back the entire transaction if either of the first two inserts fail, but it rolls

back to the named savepoint only if the third insert fails, allowing the first two to be

committed:

begin tran add_titles

insert titles (title_id, pub_id, title)

values (‘XX1234’, ‘0736’, ‘Tuning SQL Server’)

if @@error = 50000 — roll back entire transaction and abort batch

begin

rollback tran add_titles

return

end

insert titles (title_id, pub_id, title)

values (‘XX1236’, ‘0877’, ‘Tuning SQL Server’)

if @@error = 50000 — roll back entire transaction and abort batch

begin

rollback tran add_titles

return

end

save tran keep_first_two — set savepoint for partial rollback

insert titles (title_id, pub_id, title)

values (‘XX1235’, ‘abcd’, ‘Tuning SQL Server’)

if @@error = 50000 — roll back to save point, continue batch

begin

rollback tran keep_first_two

end

commit tran

TIP

When you use a savepoint inside a trigger, the trigger does not roll back the

transac-tion Therefore, the batch is not automatically aborted You must explicitly return from

the batch after rolling back the transaction to prevent subsequent statements from

executing

NOTE

Don’t forget to reenable the constraint on the titles table when you are finished

testing:

alter table titles check constraint FK titles pub_id 0F424F67

Trang 8

Transactions and Locking

SQL Server issues and holds on to locks for the duration of a transaction to ensure the

isolation and consistency of the modifications Data modifications that occur within a

transaction acquire exclusive locks, which are then held until the completion of the

trans-action Shared locks, or read locks, are held for only as long as the statement needs them;

usually, a shared lock is released as soon as data has been read from the resource (for

example, row, page, table) You can modify the length of time a shared lock is held by

using keywords such as HOLDLOCK in a query or setting the REPEATABLE_READ or

SERIALIZABLE lock isolation levels If one of these options is specified, shared locks are

held until the completion of the transaction

What this means for you as a database application developer is that you should try to

hold on to as few locks or as small a lock as possible for as short a time as possible to

avoid locking contention between applications and to improve concurrency and

applica-tion performance The simple rule when working with transacapplica-tions is to keep them short

and keep them simple In other words, you should do what you need to do in the most

concise manner, in the shortest possible time You should keep any extraneous commands

that do not need to be part of the logical unit of work—such as SELECT statements,

commands for dropping temporary tables, commands for setting up local variables, and so

on—outside the transaction

To modify the manner in which a transaction and its locks can be handled by a SELECT

statement, you can issue the SET TRANSACTION ISOLATION LEVEL statement This

state-ment allows the query to choose how much it is protected against other transactions

modifying the data being used The SET TRANSACTION ISOLATION LEVEL statement has the

following mutually exclusive options:

READ COMMITTED—This setting is the default for SQL Server Modifications made

within a transaction are locked exclusively, and the changes cannot be viewed by

other user processes until the transaction completes Commands that read data only

hold shared locks on the data for as long as they are reading it Because other

trans-actions are not blocked from modifying the data after you have read it within your

transaction, subsequent reads of the data within the transaction might encounter

nonrepeatable reads or phantom data.

READ UNCOMMITTED—With this level of isolation, one transaction can read the

modifications made by other transactions prior to being committed This is,

there-fore, the least restrictive isolation level, but it is one that allows the reading of dirty

and uncommitted data This option has the same effect as issuing NOLOCK within

SELECT statements, but it has to be set only once for your connection This option

should never be used in an application in which accuracy of the query results is

required

REPEATABLE READ—When this option is set, as data is read, locks are placed and

held on the data for the duration of the transaction These locks prevent other

trans-actions from modifying the data you have read so that you can carry out multiple

passes across the same information and get the same results each time This isolation

Trang 9

level is obviously more restrictive than READ COMMITTED and READ UNCOMMITTED, and

it can block other transactions However, although it prevents nonrepeatable reads,

it does not prevent the addition of new rows or phantom rows because only existing

data is locked

SERIALIZABLE—This option is the most restrictive isolation level because it places

a range lock on the data This prevents any modifications to the data being read

from until the end of the transaction It also avoids phantom reads by preventing

rows from being added or removed from the data range set

SNAPSHOT—Snapshot isolation specifies that data read by any statement will see

only data modifications that were committed before the start of the transaction The

effect is as if the statements in a transaction see a snapshot of the committed data as

it existed at the start of the transaction The ALLOW_SNAPSHOT_ISOLATION database

option must be set to ON for a transaction to specify the SNAPSHOT isolation level

READ_COMMITTED_SNAPSHOT Isolation

In addition to the SNAPSHOT isolation level, SQL Server also supports a special form of

read-committed isolation, referred to as READ_COMMITTED_SNAPSHOT This form of isolation is

similar to snapshot isolation, but unlike snapshot isolation, which sees the version of the

data at the start of the transaction, read committed snapshot queries see the version of the

data at the start of the statement

To enable the READ_COMMITTED_SNAPSHOT isolation level for queries, you need to enable the

READ_COMMITTED_SNAPSHOT database option Any queries that normally would run at the

standard READ_COMMITTED isolation level automatically run at the

READ_COMMITTED_SNAPSHOT isolation level, without requiring any code changes

For more information on transaction isolation levels and their effect on lock types,

locking behavior, and performance, see Chapter 37, “Locking and Performance.”

Coding Effective Transactions

Poorly written or inefficient transactions can have a detrimental effect on concurrency of

access to data and overall application performance SQL Server can hold locks on a

number of resources while the transaction is open; modified rows acquire exclusive locks,

and other locks might also be held, depending on the isolation level used To reduce

locking contention for resources, transactions should be kept as short and efficient as

possible During development, you might not even notice that a problem exists; the

problem might become noticeable only after the system load is increased and multiple

users are executing transactions simultaneously Following are some guidelines to consider

when coding transactions to minimize locking contention and improve application

performance:

Do not return result sets within a transaction Doing so prolongs the transaction

unnecessarily Perform all data retrieval and analysis outside the transaction

Trang 10

Never prompt for user input during a transaction If you do, you lose all control over

the duration of the transaction (Even the best programmers miss this one on

occa-sion.) On the failure of a transaction, be sure to issue the rollback before putting up

a message box telling the user that a problem occurred

Keep the start and end of a transaction together in the same batch or, better yet, use

a stored procedure for the operation

Keep the transaction short Start the transaction at the point where you need to do

the modifications Do any preliminary work beforehand

Make careful use of different locking schemes and transaction isolation levels

If user input is unavoidable between data retrieval and modification and you need to

handle the possibility of another user modifying the data values read, use optimistic

locking strategies or snapshot isolation rather than acquiring and holding locks by

using HOLDLOCK or other locking options Chapter 37 covers optimistic locking

methods and snapshot isolation in more detail

Collect multiple transactions into one transaction, or batch transactions together, if

appropriate This advice might seem to go against some of the other suggestions, but

it reduces the amount of overhead SQL Server will encounter to start, finish, and log

the transactions

Transaction Logging and the Recovery Process

Every SQL Server database has its own transaction log that keeps a record of all data

modi-fications in a database (for example, insert, update, delete) in the order in which they

occur This information is stored in one or more log files associated with the database The

information stored in these log files cannot be modified or viewed effectively by any user

process

SQL Server uses a write-ahead log The buffer manager guarantees that changes are written

to the transaction log before the changes are written to the database The buffer manager

also ensures that the log pages are written out in sequence so that transactions can be

recovered properly in the event of a system crash

The following is an overview of the sequence of events that occurs when a transaction

modifies data:

1 Writes a BEGIN TRAN record to the transaction log in buffer memory

2 Writes data modification information to transaction log pages in buffer memory

3 Writes data modifications to the database in buffer memory

4 Writes a COMMIT TRAN record to the transaction log in buffer memory

5 Writes transaction log records to the transaction log file(s) on disk

6 Sends a COMMIT acknowledgment to the client process

Ngày đăng: 05/07/2014, 02:20

TỪ KHÓA LIÊN QUAN