本文转自:http://geekswithblogs.net/bbiales/archive/2012/03/15/how-to-nest-transactions-nicely---quotbegin-transactionquot-vs-quotsave.aspx

Do you write stored procedures that might be used by others?  And those others may or may not have already started a transaction?  And your SP does several things, but if any of them fail, you have to undo them all and return with a code indicating it failed?

Well, I have written such code, and it wasn’t working right until I finally figured out how to handle the case when we are already in a transaction, as well as the case where the caller did not start a transaction.  When a problem occurred, my “ROLLBACK TRANSACTION” would roll back not just my nested transaction, but the caller’s transaction as well.  So when I tested the procedure stand-alone, it seemed to work fine, but when others used it, it would cause a problem if it had to rollback.  When something went wrong in my procedure, their entire transaction was rolled back.  This was not appreciated.

Now, I knew one could "nest" transactions, but the technical documentation was very confusing.  And I still have not found the approach below documented anywhere.  So here is a very brief description of how I got it to work, I hope you find this helpful.

My example is a stored procedure that must figure out on its own if the caller has started a transaction or not.  This can be done in SQL Server by checking the @@TRANCOUNT value.  If no BEGIN TRANSACTION has occurred yet, this will have a value of 0.  Any number greater than zero means that a transaction is in progress.  If there is no current transaction, my SP begins a transaction. But if a transaction is already in progress, my SP uses SAVE TRANSACTION and gives it a name.  SAVE TRANSACTION creates a “save point”.  Note that creating a save point has no effect on @@TRANCOUNT.

So my SP starts with something like this:

DECLARE @startingTranCount int
SET @startingTranCount = @@TRANCOUNT IF @startingTranCount > 0
SAVE TRANSACTION mySavePointName
ELSE
BEGIN TRANSACTION
-- …


Then, when ready to commit the changes, you only need to commit if we started the transaction ourselves:

IF @startingTranCount = 0
COMMIT TRANSACTION

And finally, to roll back just your changes so far:

-- Roll back changes...
IF @startingTranCount > 0
ROLLBACK TRANSACTION MySavePointName
ELSE
ROLLBACK TRANSACTION

Here is some code that you can try that will demonstrate how the save points work inside a transaction.

This sample code creates a temporary table, then executes selects and updates, documenting what is going on, then deletes the temporary table.

if running in SQL Management Studio, set Query Results to: Text for best readability of the results.

-- Create a temporary table to test with, we'll drop it at the end.
CREATE TABLE #ATable(
[Column_A] [varchar](5) NULL
) ON [PRIMARY] GO
SET NOCOUNT ON
-- Ensure just one row - delete all rows, add one
DELETE #ATable
-- Insert just one row
INSERT INTO #ATable VALUES('000') SELECT 'Before TRANSACTION starts, value in table is: ' AS Note, * FROM #ATable SELECT @@trancount AS CurrentTrancount
--insert into a values ('abc')
UPDATE #ATable SET Column_A = 'abc'
SELECT 'UPDATED without a TRANSACTION, value in table is: ' AS Note, * FROM #ATable
BEGIN TRANSACTION
SELECT 'BEGIN TRANSACTION, trancount is now ' AS Note, @@TRANCOUNT AS TranCount
UPDATE #ATable SET Column_A = '123'
SELECT 'Row updated inside TRANSACTION, value in table is: ' AS Note, * FROM #ATable
SAVE TRANSACTION MySavepoint
SELECT 'Save point MySavepoint created, transaction count now:' as Note, @@TRANCOUNT AS TranCount
UPDATE #ATable SET Column_A = '456'
SELECT 'Updated after MySavepoint created, value in table is: ' AS Note, * FROM #ATable
SAVE TRANSACTION point2
SELECT 'Save point point2 created, transaction count now:' as Note, @@TRANCOUNT AS TranCount
UPDATE #ATable SET Column_A = '789'
SELECT 'Updated after point2 savepoint created, value in table is: ' AS Note, * FROM #ATable
ROLLBACK TRANSACTION point2
SELECT 'Just rolled back savepoint "point2", value in table is: ' AS Note, * FROM #ATable
ROLLBACK TRANSACTION MySavepoint
SELECT 'Just rolled back savepoint "MySavepoint", value in table is: ' AS Note, * FROM #ATable
SELECT 'Both save points were rolled back, transaction count still:' as Note, @@TRANCOUNT AS TranCount
ROLLBACK TRANSACTION
SELECT 'Just rolled back the entire transaction..., value in table is: ' AS Note, * FROM #ATable DROP TABLE #ATable

[转]How to nest transactions nicely - "begin transaction" vs "save transaction" and SQL Server的更多相关文章

  1. 事务操作(BEGIN/COMMIT/ROLLBACK/SAVE TRANSACTION)

    BEGIN TRANSACTION 标记一个显式本地事务的起始点. BEGIN TRANSACTION 使 @@TRANCOUNT 按 1 递增. BEGIN TRANSACTION 代表一点,由连接 ...

  2. SQL SAVE TRANSACTION

    --创建存储过程 create procedure qiantaoProc @asd nchar(10) as begin begin try begin transaction innerTrans ...

  3. SQL Server does not purge row versioning records even the transaction are committed if there are other open transaction running in the databases with read-committed snapshot enabled .

    This is a by-design behavior. There is only one allocation unit in tempdb that istracking the versio ...

  4. [转]sql server transaction

    本文转自: http://www.2cto.com/database/201208/146734.html sql事务(Transaction)用法介绍及回滚实例   事务(Transaction)是 ...

  5. sql server 学习笔记 (nested transaction 嵌套事务)

    什么时候会用到嵌套事务 ? 为了代码复用,我们会写许多的储蓄过程,而中间如果需要使用到 transaction 难免就会发生嵌套了. sql server 并不直接支持嵌套事务. 但它可以用一些招式来 ...

  6. SQL Server 数据库的维护(三)__事务(transaction)和锁

    --维护数据库-- --事务(transaction)和锁-- --事务(transaction)-- --概述: 事务是指封装了一组T-SQL语句的单个逻辑单元.单元中的所有语句作为一个整体,在满足 ...

  7. [杂]SQL Server 之 Understanding Connection Pooling and Transactions

    A SqlConnection consists of two parts: the public instance that your code interacts with (the outer ...

  8. SQL Server save transaction

    准备: create table Nums(X int); 目的:只向表中插入一行. --------------------------------------------------------- ...

  9. [官网]How to use distributed transactions with SQL Server on Docker

    How to use distributed transactions with SQL Server on Docker https://docs.microsoft.com/en-us/sql/l ...

随机推荐

  1. Flash(as3) 调整显示对象颜色

    在游戏开发中改变显示对象的颜色是比较常见的操作,那么除了在FlashCS中调整,AS3又提供了怎样的方式呢? ColorTransform 这个类是轻量级的应用,其构造参数如下: ColorTrans ...

  2. C#文件监控对象FileSystemWatcher实例,通过监控文件创建、修改、删除、重命名对服务器数据进行实时备份

    先上图,简单的windorm界面:此为最初的版本,后续会增加监听多个源目录的功能.log功能.进度条展示功能等. 1.初始化监听 /// <summary> /// 初始化监听 /// & ...

  3. 浅析C# Dictionary实现原理

    目录 一.前言 二.理论知识 1.Hash算法 2.Hash桶算法 3.解决冲突算法 三.Dictionary实现 1. Entry结构体 2. 其它关键私有变量 3. Dictionary - Ad ...

  4. C#获取微信二维码显示到wpf

    微信的api开放的二维码是一个链接地址,而我们要将这个二维码显示到客户端.方式很多,今天我们讲其中一种. /// <summary> /// 获取图片路径 /// </summary ...

  5. Json/XML序列化和反序列化

    1.json序列化和反序列化 序列化是将对象状态转换为可保持或传输的格式的过程; 反序列化,它将流转换为对象; 1)Json.Net 推荐使用Json.Net类库,需要引入的命名空间; 序列化:Jso ...

  6. 批处理系列(18) - 基于BitLocker的开锁上锁

    首先要配置好BitLocker. 上锁 lock.bat @echo off rem 上锁前要结束一些程序,浏览器要注意:有恢复上次关闭项功能,按需设置取消该操作 taskkill /f /t /im ...

  7. Day44 数据库的操作

    视图操作: 1.左连接查询 select * from person left join dept on person.dept_id = dept.did 2. 右连接 3. 内连接  inner ...

  8. Hash Table-720. Longest Word in Dictionary

    Given a list of strings words representing an English Dictionary, find the longest word in words tha ...

  9. 简述在MySQL数据库中MyISAM和InnoDB的区别

    区别主要有以下几点: (1)构成上,MyISAM的表在磁盘中有三个文件组成,分别是表定义文件(.frm).数据文件(.MYD).索引文件(.MYI),而InnoDB的表由表定义文件(.frm).表空间 ...

  10. Swift 里字符串(九)UTF16View

    即以 UTF16 编码的格式来查看字符串. UTF16View 是一个结构体 @_fixed_layout public struct UTF16View { @usableFromInline in ...