[转]How to nest transactions nicely - "begin transaction" vs "save transaction" and SQL Server
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的更多相关文章
- 事务操作(BEGIN/COMMIT/ROLLBACK/SAVE TRANSACTION)
BEGIN TRANSACTION 标记一个显式本地事务的起始点. BEGIN TRANSACTION 使 @@TRANCOUNT 按 1 递增. BEGIN TRANSACTION 代表一点,由连接 ...
- SQL SAVE TRANSACTION
--创建存储过程 create procedure qiantaoProc @asd nchar(10) as begin begin try begin transaction innerTrans ...
- 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 ...
- [转]sql server transaction
本文转自: http://www.2cto.com/database/201208/146734.html sql事务(Transaction)用法介绍及回滚实例 事务(Transaction)是 ...
- sql server 学习笔记 (nested transaction 嵌套事务)
什么时候会用到嵌套事务 ? 为了代码复用,我们会写许多的储蓄过程,而中间如果需要使用到 transaction 难免就会发生嵌套了. sql server 并不直接支持嵌套事务. 但它可以用一些招式来 ...
- SQL Server 数据库的维护(三)__事务(transaction)和锁
--维护数据库-- --事务(transaction)和锁-- --事务(transaction)-- --概述: 事务是指封装了一组T-SQL语句的单个逻辑单元.单元中的所有语句作为一个整体,在满足 ...
- [杂]SQL Server 之 Understanding Connection Pooling and Transactions
A SqlConnection consists of two parts: the public instance that your code interacts with (the outer ...
- SQL Server save transaction
准备: create table Nums(X int); 目的:只向表中插入一行. --------------------------------------------------------- ...
- [官网]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 ...
随机推荐
- ASP.NET MVC URL重写与优化(初级篇)-使用Global路由表定制URL
ASP.NET MVC URL重写与优化(初级篇)-使用Global路由表定制URL 引言--- 在现今搜索引擎制霸天下的时代,我们不得不做一些东西来讨好爬虫,进而提示网站的排名来博得一个看得过去的流 ...
- 零开始:NetCore项目权限管理系统:登录授权
喜欢NetCore的朋友,欢迎加群QQ:86594082 源码地址:https://github.com/feiyit/SoaProJect 管理员的模型 namespace FytSoa.Core. ...
- 2D and 3D Linear Geometry Kernel ( Geometry Kernels) CGAL 4.13 -User Manual
1 Introduction CGAL, the Computational Geometry Algorithms Library, is written in C++ and consists o ...
- java程序中获取kerberos登陆hadoop
本文由作者周梁伟授权网易云社区发布. 一般我们在使用kbs登陆hadoop服务时都直接在shell中调用kinit命令来获取凭证,这种方式简单直接,只要获取一次凭证之后都可以在该会话过程中重复访问.但 ...
- 实现单台测试机6万websocket长连接
本文由作者郑银燕授权网易云社区发布. 本文是我在测试过程中的记录,实现了单台测试机发起最大的websocket长连接数.在一台测试机上,连接到一个远程服务时的本地端口是有限的.根据TCP/IP协议,由 ...
- Flask基础-基础实例
1. 10行代码的迷你程序 flask项目 from flask import Flask app = Flask(__name__) @app.route("/index") d ...
- Mac OS 10.12 - 如何能够像在Windows一样切换中英文输入法和大小写键?
最开始,我切换中英文输入法和大小写键是按照下面博客做到的: http://www.cnblogs.com/sunylat/p/6415563.html 但是当我安装完毕搜狗输入法后,切换中英文输入法和 ...
- JVM之JIT
JIT技术是JVM中最重要的核心模块之一.我的课程里本来没有计划这一篇,但因为不断有朋友问起,Java到底是怎么运行的?既然Hotspot是C++写的,那Java是不是可以说运行在C++之上呢?为了澄 ...
- absolute
在需要用到小图标时,可以使用position:absolute,它具有消除float和位置不变特性.使用absolute可以浮现在同级元素的上方.用margin进行精确定位即可,也不必使用top,le ...
- Android启动过程介绍
开机过程大致可以分为以下三个阶段 OS级别 由bootloader载入linux kernel后,kernel开始初始化, 并载入built-in的驱动程序.Kernel完成开机后,载入init pr ...