事务

Transact-SQL provides three different methods of transaction control: autocommit transactions, explicit transactions and implicit transactions.

An autocommit transaction is any individual INSERT, UPDATE or DELETE operation, no matter how many rows are affected. As soon as the statement is completed, it is committed, which means that all the corresponding log records, include a COMMIT TRAN log record, are written to the transaction log on disk (your .ldf file).

If you want to be able to combine multiple statements into a single transaction, or if you want to be able to conditionally rollback the transaction, you can use explicit transaction control, with the BEGIN TRANSACTION (or BEGIN TRAN) and COMMIT TRANSACTION (or COMMIT TRAN) control statements. For example, to make sure both T1 and T2 are updated, or neither one is updated, you can use the following pseudo-code:

BEGIN TRAN
    UPDATE T1 ...
    UPDATE T2 ...
COMMIT TRAN  

If there is a system failure after T1 is updated, the transaction will not be committed. It will only be committed if both updates can succeed.

Also, by using explicit transactions, you can decide to rollback a transaction, after checking for an error condition or for the number of rows affected:

BEGIN TRAN
    UPDATE T1 ...
    IF @@error > 0 ROLLBACK TRAN
        ELSE COMMIT TRAN  

The third type of transaction control, implicit transactions, is not considered a default behavior and is part of the product only to support compatibility with other database products. I'll say a couple of things about it shortly.

Here is a little quiz I frequently give my students. Suppose I have the following batch:

BEGIN TRAN
UPDATE T1
BEGIN TRAN
UPDATE T2
BEGIN TRAN
UPDATE T3
COMMIT TRAN

The quiz question is: What gets committed?

I usually get a variety of answers including: All the updates, none of the updates, the update to T1, the update to T3. (Nobody suggests the update to T2.)

It turns out the answer is: None of the above.

SQL Server keeps an internal counter of how many times BEGIN TRAN has been executed, and you need to execute the same number of COMMIT TRANs to get the real commit to take place. Each BEGIN TRAN increments this internal counter, and each COMMIT TRAN decrements it. Only when the counter gets to 0, will the log records be written out to disk and the transaction will be truly committed. You can look at the value of this counter with the function @@trancount. You can use this function to also see that when you do a ROLLBACK, the counter is immediately set all the way back to 0.

BEGIN TRAN
SELECT @@trancount
BEGIN TRAN
SELECT @@trancount
BEGIN TRAN
SELECT @@trancount

ROLLBACK TRAN
SELECT @@trancount

So why would you want to have nested transactions, if it really doesn't give you any advantage?  The answer to that will have to wait for a future post. This post is about the relationship of nesting transactions to the third type of transaction control: implicit transactions.

The name 'implicit transactions' is a bit of a misnomer. It is only the BEGIN TRAN that is implicit; the COMMIT TRAN must always be explicit. This means that no transaction will be committed until a COMMIT TRAN is issued. Transactions will begin any time an INSERT, UPDATE, DELETE or SELECT is executed (as well as a few other statements, such as CREATE and DROP, that you can read about in the Books Online) as long as there is not already an open transaction.

As mentioned, implicit transaction mode is not SQL Server's default. You have to request implicit transaction mode either with a SET statement:

SET IMPLICIT_TRANSACTIONS ON;

or by setting the user_options configuration option to have the 2-bit set to 1. You can read about sp_configure 'user options' in the Books Online. Although I don't recommend using implicit transactions, if you're going to use them, I recommend having all sessions use them, but setting the configuration option. To have some sessions using implicit transactions and requiring a COMMIT for every individual INSERT, UPDATE and DELETE and to have other sessions not requiring that closure, seems to be asking for trouble.

So what happens if you use a BEGIN TRAN when you are in implicit transaction mode? I used to think that the BEGIN TRAN would just be ignored, but it turns out I was wrong. Think about what would happen if you had a normal, implicit mode transaction like this:

UPDATE T1
    SET ...
COMMIT TRAN

and then suppose someone executes this batch from within an explicit transaction, and put the BEGIN/COMMIT around it:

BEGIN TRAN
UPDATE T1
    SET ...
COMMIT TRAN
COMMIT TRAN

If the BEGIN TRAN was ignored, the first COMMIT would would set @@trancount to 0 and the second would give an error. You can see this behavior by just executing COMMIT TRAN all by itself. SQL Server generates this message:

Msg 3902, Level 16, State 1, Line 1
The COMMIT TRANSACTION request has no corresponding BEGIN TRANSACTION.

So if you are in implicit transaction mode, issuing a BEGIN TRAN (which you really shouldn't do) sets @@trancount to 2. This really surprised me when I first noticed it, but then I realized the point of it. When you perform any DML operation, since you are already in a transaction, @@trancount will not be incremented. When you issue the COMMIT for your DML, @@trancount will be decremented to 1. When you issue the COMMIT TRAN to match the BEGIN TRAN, @@trancount will decrement to 0 and the transaction will really be committed.  Here's a full script to illustrate the behavior of @@trancount with implicit transactions:

SET IMPLICIT_TRANSACTIONS OFF;
GO
IF EXISTS (SELECT * FROM sys.objects
WHERE name = 'T1' AND type = 'U')
DROP TABLE T1;
GO
CREATE TABLE T1 (col1 int);
GO
INSERT INTO T1 SELECT 1;
GO

SET IMPLICIT_TRANSACTIONS ON;
GO
BEGIN TRAN;
SELECT @@trancount;
UPDATE T1
SET col1 = col1 + 1;
COMMIT TRAN;
SELECT @@trancount;
COMMIT TRAN;
SELECT @@trancount;
GO
SET IMPLICIT_TRANSACTIONS OFF;
GO

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值