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

Microsoft SQL Server 2008 R2 Unleashed- P107 doc

10 305 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 205,1 KB

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

Nội dung

CHAPTER 31 Transaction Management and the Transaction Log begin a multistatement transaction that remains in effect until an explicit ROLLBACK or COMMIT statement is issued.. Even when u

Trang 1

CHAPTER 31 Transaction Management and the Transaction Log

begin a multistatement transaction that remains in effect until an explicit ROLLBACK or

COMMIT statement is issued Microsoft refers to this transation mode as IMPLICIT_

TRANSACTIONS

To enable implicit transactions for a connection in SQL Server 2008, you need to enable

the IMPLICIT_TRANSACTIONS session setting using the following command:

SET IMPLICIT_TRANSACTIONS ON

After this option is turned on, transactions are implicitly started, if they are not already in

progress, whenever any of the following commands are executed:

ALTER TABLE

CREATE

DELETE

DROP

FETCH

GRANT

INSERT

OPEN

REVOKE

SELECT

TRUNCATE TABLE

UPDATE

Note that neither the ALTER VIEW nor ALTER PROCEDURE statement starts an implicit

transaction

You must explicitly complete implicit transactions by issuing a COMMIT or ROLLBACK; a new

transaction is started again on the execution of any of the preceding commands If you

plan to use implicit transactions, the main issue to be aware of is that locks are held until

you explicitly commit the transaction This can cause problems with concurrency and the

system’s capability to truncate the transaction log

Even when using implicit transactions, you can still issue the BEGIN TRAN statement and

create transaction nesting In the following example, IMPLICIT_TRANSACTIONS ON is turned

on to see the effect this has on the value of @@trancount

SQL Statements @@trancount Value

SET IMPLICIT_TRANSACTIONS ON 0

Trang 2

As you can see in this example, if a BEGIN TRAN is issued while a transaction is still active,

transaction nesting occurs, and a second COMMIT is required to finish the transaction The

main difference between this example and the preceding one is that here, a BEGIN TRAN is

not required to start the transaction The first INSERT statement initiates the transaction

When you are running in implicit transaction mode, you don’t need to issue a BEGIN TRAN

statement; in fact, you should avoid doing so to prevent transaction nesting and the need

for multiple commits

The following example shows the previous banking transaction using implicit

transactions:

set implicit_transactions on

go

declare @checking_account char(10),

@savings_account char(10)

select @checking_account = ‘0003456321’,

@savings_account = ‘0003456322’

update account

set balance = balance - $1000

where account_number = @checking_account

if @@error != 0

begin

rollback

return

end

update savings_account

set balance = balance + $1000

where account_number = @savings_account

if @@error != 0

begin

rollback

go

SELECT * FROM table1 1

go

Trang 3

CHAPTER 31 Transaction Management and the Transaction Log

return

end

commit

This example is nearly identical to the explicit transaction example except for the lack of a

BEGIN TRAN statement In addition, when in implicit transaction mode, you cannot roll

back to a named transaction because no name is assigned when the transaction is invoked

implicitly You can, however, still set savepoints and roll back to savepoints to partially

roll back work within an implicit transaction

TIP

If you need to know within your SQL code whether implicit transactions are enabled so

you can avoid issuing explicit BEGIN TRAN statements, you can check the @@options

function @@options returns a bitmap that indicates which session-level options are

enabled for the current session If bit 2 is on, implicit transactions are enabled The

following code snippet can be used in stored procedures or SQL batches to check this

value and decide whether to issue a BEGIN TRAN statement:

if @@options & 2 != 2 — if bit 2 is not turned on

BEGIN TRAN —a begin tran can be issued since implicit transactions

are off

Implicit Transactions Versus Explicit Transactions

When would you want to use implicit transactions versus explicit transactions? If you are

porting an application from another database environment, such as DB2 or Oracle, that

uses implicit transactions, that application converts over to SQL Server more easily and

with fewer code changes if you run in implicit transaction mode Also, if the application

you are developing needs to be ANSI compliant and run across multiple database

plat-forms with minimal code changes, you might want to use implicit transactions

If you use implicit transactions in your applications, you need to be sure to issue COMMIT

statements as frequently as possible to prevent leaving transactions open and holding

locks for an extended period of time, which can have an adverse impact on concurrency

and overall system performance

If an application is going to be hosted only on SQL Server, it is recommended that you use

AutoCommit and explicit transactions so that changes are committed as quickly as

possi-ble and so that only those logical units of work that are explicitly defined contain

multi-ple commands within a transaction

Trang 4

Transactions and Batches

There is no inherent transactional quality to batches As you have seen already, unless you

provide the syntax to define a single transaction made up of several statements, each

indi-vidual statement in a batch is its own separate transaction, and each statement is carried

to completion or fails individually

The failure of a transaction within a batch does not cause the batch to stop processing In

other words, transaction flow does not affect process flow After a ROLLBACK TRAN

state-ment, processing continues with the next statement in the batch or stored procedure For

this reason, you should be sure to check for error conditions after each data modification

within a transaction and exit the batch or stored procedure, as appropriate

Consider the banking transaction again, this time removing the RETURN statements:

declare @checking_account char(10),

@savings_account char(10)

select @checking_account = ‘0003456321’,

@savings_account = ‘0003456322’

begin tran

update account

set balance = balance - $1000

where account_number = @checking_account

if @@error != 0

rollback tran

update savings_account

set balance = balance + $1000

where account_number = @savings_account

if @@error != 0

rollback tran

commit tran

Assume that a check constraint on the account prevents the balance from being set to a

value less than 0 If the checking account has less than $1,000 in it, the first update fails,

and the T-SQL code catches the error condition and rolls back the transaction At this

point, the transaction is no longer active, but the batch still contains additional

state-ments to execute Without a return after the rollback, SQL Server continues with the next

statement in the batch, which in this case is the update to the savings account However,

this now executes as its own separate transaction, and it automatically commits if it

completes successfully This is not the result you want because now that second update is

its own separate unit of work, so you have no way to roll it back

The key concept to keep in mind here is that transaction flow does not affect program

flow In the event of an error within a transaction, you need to make sure you have the

proper error checking and a means to exit the transaction in the event of an error This

Trang 5

CHAPTER 31 Transaction Management and the Transaction Log

prevents the batch from continuing with any remaining modifications that were meant to

be a part of the original transaction As a general rule, a RETURN statement should almost

always follow a rollback

In addition to being able to define multiple transactions within a batch, you can also have

transactions that span multiple batches For example, you could write an application that

begins a transaction in one batch and then asks for user verification during a second batch

The SQL might look like this:

First batch:

use bigpubs2008

go

begin transaction

insert publishers (pub_id, pub_name, city, state)

values (‘1111’, ‘Joe and Marys Books’, ‘Northern Plains’, ‘IA’)

if @@error = 0

print ‘publishers insert was successful Please go on.’

else

print ‘publisher insert failed Please roll back’

Second batch:

update titles

set pub_id = ‘1111’

where pub_id = ‘1234’

delete authors

where state = ‘CA’

commit transaction

Writing transactions that span multiple batches is almost always a bad idea The locking and

concurrency problems can become complicated, with awful performance implications

What if the application prompted for user input between batches, and the user went out to

lunch? Locks would be held until the user got back and continued the transaction In

general, you want to enclose each transaction in a single batch, using conditional

program-ming constructs to handle situations like the preceding example Following is a better way

to write that code:

begin transaction

insert publishers (pub_id, pub_name, city, state)

values (‘1111’, ‘Joe and Marys Books’, ‘Northern Plains’, ‘IA’)

if @@error = 0

begin

print ‘publishers insert was successful Continuing.’

update titles

set pub_id = ‘1111’

where pub_id = ‘1234’

Trang 6

where state = ‘CA’

commit transaction

end

else

begin

print ‘publisher insert failed rolling back transaction’

rollback transaction

end

The important point in this example is that the transaction now takes place within a

single batch for better performance and consistency As you see in the next section, it is

usually best to encode transactions in stored procedures for even better performance and

to avoid the possibility of unfinished transactions

Transactions and Stored Procedures

Because SQL code in stored procedures runs locally on the server, it is recommended that

entire transactions be completely encapsulated within stored procedures to speed

transac-tion processing This way, the entire transactransac-tion executes within a single stored procedure

call from the client application, rather than being executed across multiple requests The

less network traffic that occurs between the client application and SQL Server during

transactions, the faster they can finish

Another advantage of using stored procedures for transactions is that doing so helps you

avoid the occurrence of partial transactions—that is, transactions that are started but not

fully committed Using stored procedures this way also avoids the possibility of user

inter-action within a transinter-action The stored procedure keeps the transinter-action processing

completely contained because it starts the transaction, carries out the data modifications,

completes the transaction, and returns the status or data to the client

Stored procedures also provide the additional benefit that if you need to fix, fine-tune, or

expand the duties of the transaction, you can do all this at one time, in one central

loca-tion Your applications can share the same stored procedure, providing consistency for the

logical unit of work across your applications

Although stored procedures provide a useful solution to managing transactions, you need

to know how transactions work within stored procedures and code for them appropriately

Consider what happens when one stored procedure calls another, and they both do their

own transaction management Obviously, they now need to work in concert with each

other If the called stored procedure has to roll back its work, how can it do so correctly

without causing data integrity problems?

The issues you need to deal with go back to the earlier topics of transaction nesting and

transaction flow versus program flow Unlike a rollback in a trigger (see the next section),

a rollback in a stored procedure does not abort the rest of the batch or the calling

proce-dure

Trang 7

CHAPTER 31 Transaction Management and the Transaction Log

For each BEGIN TRAN encountered in a nested procedure, the transaction nesting level is

incremented by 1 For each COMMIT encountered, the transaction nesting level is

decre-mented by 1 However, if a rollback other than to a named savepoint occurs in a nested

procedure, it rolls back all statements to the outermost BEGIN TRAN, including any work

performed inside the nested stored procedures that has not been fully committed It then

continues processing the remaining commands in the current procedure as well as the

calling procedure(s)

To explore the issues involved, you can work with the sample stored procedure shown in

Listing 31.1 The procedure takes a single integer argument, which it then attempts to

insert into a table (test_table) All data entry attempts—whether successful or not—are

logged to a second table (auditlog) Listing 31.1 contains the code for the stored

proce-dure and the tables it uses

LISTING 31.1 Sample Stored Procedure and Tables for Transaction Testing

CREATE TABLE test_table (col1 int)

go

CREATE TABLE auditlog (who varchar(128), valuentered int null)

go

CREATE PROCEDURE trantest @arg INT

AS

BEGIN TRAN

IF EXISTS( SELECT * FROM test_table WHERE col1 = @arg )

BEGIN

RAISERROR (‘Value %d already exists!’, 16, -1, @arg)

ROLLBACK TRANSACTION

END

ELSE

BEGIN

INSERT INTO test_table (col1) VALUES (@arg)

COMMIT TRAN

END

INSERT INTO auditlog (who, valuentered) VALUES (USER_NAME(), @arg)

return

Now explore what happens if you call this stored procedure in the following way and

check the values of the two tables:

set nocount on

EXEC trantest 1

EXEC trantest 2

SELECT * FROM test_table

SELECT valuentered FROM auditlog

Trang 8

The execution of this code gives the following results:

col1

—————-1

2

valuentered

—————-1

2

These would be the results you would expect because no errors would occur, and nothing

would be rolled back

Now, if you were to run the same code a second time, test_table would still have only

two rows because the procedure would roll back the attempted insert of the duplicate

rows However, because the procedure and batch are not aborted, the code would

continue processing, and the rows would still be added to the auditlog table The result

would be as follows:

set nocount on

EXEC trantest 1

EXEC trantest 2

SELECT * FROM test_table

SELECT valuentered FROM auditlog

go

Msg 50000, Level 16, State 1, Procedure trantest, Line 6

Value 1 already exists!

Msg 50000, Level 16, State 1, Procedure trantest, Line 6

Value 2 already exists!

col1

—————-1

2

valuentered

—————-1

2

1

2

Trang 9

CHAPTER 31 Transaction Management and the Transaction Log

Now explore what happens when you execute the stored procedure from within a

transac-tion:

set nocount on

BEGIN TRAN

EXEC trantest 3

EXEC trantest 1

EXEC trantest 4

COMMIT TRAN

SELECT * FROM test_table

SELECT valuentered FROM auditlog

go

The execution of this code gives the following results:

Msg 50000, Level 16, State 1, Procedure trantest, Line 6

Value 1 already exists!

Msg 266, Level 16, State 2, Procedure trantest, Line 0

Transaction count after EXECUTE indicates that a COMMIT or ROLLBACK TRANSACTION

statement is missing Previous count = 1, current count = 0

Msg 3902, Level 16, State 1, Line 6

The COMMIT TRANSACTION request has no corresponding BEGIN TRANSACTION

col1

—————-1

2

4

valuentered

—————-1

2

1

2

1

4

A number of problems are occurring now For starters, you get a message telling you that

the transaction nesting level was messed up More seriously, the results show that the

value 4 made it into the test_table table anyway and that the auditlog table picked up

the inserts of 1 and the 4 but lost the fact that you tried to insert a value of 3 What

happened?

Trang 10

Let’s examine this example one step at a time First, you start the transaction and insert

the value 3 into trantest The stored procedure starts its own transaction, adds the value

to test_table, commits that, and then adds a row to auditlog Next, you execute the

procedure with the value 1 This value already exists in the table, so the procedure raises

an error and rolls back the transaction Remember that a ROLLBACK undoes work to the

outermost BEGIN TRAN—which means the start of this batch This rolls back everything,

including the insert of 3 into trantest and auditlog The auditlog entry for the value 1

is inserted and not rolled back because it occurred after the transaction was rolled back

and is a standalone, automatically committed statement now

You then receive an error regarding the change in the transaction nesting level because a

transaction should leave the state of a governing procedure in the same way it was

entered; it should make no net change to the transaction nesting level In other words,

the value of @@trancount should be the same when the procedure exits as when it was

entered If it is not, the transaction control statements are not properly balanced

Also, because the batch is not aborted, the value 4 is inserted into trantest, an operation

that completes successfully and is automatically committed Finally, when you try to

commit the transaction, you receive the last error regarding a mismatch between BEGIN

TRAN and COMMIT TRAN because no transaction is currently in operation

The solution to this problem is to write the stored procedures so that transaction nesting

doesn’t occur and so the stored procedure rolls back only its own work When a rollback

occurs, it should return an error status so that the calling batch or procedure is aware of

the error condition and can choose to continue or abort the work at that level You can

manage this by checking the current value of @@trancount and determining what needs to

be done If a transaction is already active, the stored procedure should not issue a BEGIN

TRAN and nest the transaction; rather, it should set a savepoint This allows the procedure

to perform a partial rollback of its work If no transaction is active, the procedure can

safely begin a new transaction The following SQL code fragment is an example of using

this approach:

DECLARE @trancount INT

/* Capture the value of the transaction nesting level at the start */

SELECT @trancount = @@trancount

IF (@trancount = 0) — no transaction is currently active, start one

BEGIN TRAN mytran

ELSE — a transaction is active, set a savepoint only

SAVE TRAN mytran

/* This is how to trap an error Roll back either to your

own BEGIN TRAN or roll back to the savepoint Return an

error code to the caller to indicate an internal failure

How the caller handles the transaction is up to the caller.*/

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

TỪ KHÓA LIÊN QUAN