在 SQL Server 2014 中使用带有事务的存储过程的 TransactionScope

2024-06-26

我正在使用 C# 和 ADO.NetTransactionScope在 ASP.Net 应用程序中运行事务。该事务应该在多个表中保存一些数据,然后向订阅者发送电子邮件。

Question: 是否有效使用TransactionScope,当它包含对在 SQL Server 2014 中拥有自己的事务的存储过程的调用时,或者我应该删除 SQL 事务语句,即begin tran, commit tran and rollback tran在此调用的存储过程中的语句TransactionScope?

下面提到了该场景的C#代码以及存储过程的T-SQL代码。

C# 代码使用TransactionScope:

  try 
    {
        using (TransactionScope scope = new TransactionScope())
        {
            using (SqlConnection connection1 = new SqlConnection(connectString1))
            {
                // Opening the connection automatically enlists it in the  
                // TransactionScope as a lightweight transaction.
                connection1.Open();

                // SaveEmailData is a stored procedure that has a transaction within it
                SqlCommand command1 = new SqlCommand("SaveEmailData", connection1);
                command1.CommandType = CommandType.StoredProcedure;
                command1.ExecuteNonQuery();

            }

            //Send Email using the helper method
            EmailHelper.SendCustomerEmails(customerIds);

            // The Complete method commits the transaction. If an exception has been thrown, 
            // Complete is not  called and the transaction is rolled back.
            scope.Complete();

        }
    }
    catch( Exception ex)
    {
       Logger.Log(ex);
    }

存储过程的T-SQLSaveEmailData:

SET NOCOUNT ON

    BEGIN TRY
        DECLARE @emailToUserId BIGINT

        BEGIN TRAN
        -- //update statement. detail statement omitted
        UPDATE TABLE1...

         --update statement. detail statement omitted
        UPDATE TABLE2...

        IF @@trancount > 0
        BEGIN
            COMMIT TRAN
        END
    END TRY

    BEGIN CATCH

        IF @@TRANCOUNT > 0
        BEGIN
            ROLLBACK TRAN
        END

        EXEC Error_RaiseToADONET

    END CATCH

Yes, TransactionScope包装 SQL 时仍然可以工作BEGIN / COMMIT TRANSACTION或 ADOSqlConnection.BeginTransaction。包装单个连接时,行为类似于将事务嵌套在Sql:

  • @@TranCount将在每个BEGIN TRAN

  • COMMIT TRAN只会减少@@TRANCOUNT。只有在以下情况下才会提交事务@@TRANCOUNT为零。

However:

  • ROLLBACK TRAN将中止整个交易(即),除非您正在使用保存积分 https://technet.microsoft.com/en-us/library/ms178157(v=sql.105).aspx (i.e. SAVE TRANSACTION xx ... ROLLBACK TRANSACTION xx.
  • 使用存储过程时,如果连接不正确,您将收到错误@@TRANCOUNT退出 SPROC 时的值与进入 SPROC 时的值不同。

因此,通常更容易将事务语义留给TransactionScope并删除任何手册BEGIN TRAN / COMMIT TRAN逻辑不会让你的 TSQL 变得混乱。

Edit- 澄清以下评论

  • 在OP的情况下,SPROC在编写时并没有考虑到嵌套事务(即是否由Sql或.Net外部事务包装),具体来说,ROLLBACK in the BEGIN CATCH块将中止整个外部事务,并可能导致外部发生进一步的错误TransactionScope as the @@TRANCOUNT规则未被遵守。 A像这样的嵌套事务模式 http://rusanu.com/2009/06/11/exception-handling-and-nested-transactions/如果 SPROC 需要以嵌套或独立事务方式操作,则应注意。

  • SavePoints 不适用于分布式事务 http://www.sommarskog.se/wishlist.html#savepointdistr, and TransactionScope可以轻松地升级为分布式事务 https://stackoverflow.com/a/22512547/314291例如如果您在事务范围内使用不同的连接字符串或控制其他资源。

因此,我建议将 PROC 重构为“快乐”的核心/内部情况,从事务范围调用此内部过程,并在那里进行任何异常处理和回滚。如果您还需要从 Ad Hoc Sql 调用 proc,则提供一个具有异常处理功能的外部包装器 Proc:

-- Just the happy case. This is called from .Net TransactionScope
CREATE PROC dbo.InnerNonTransactional
  AS
    BEGIN 
      UPDATE TABLE1...
      UPDATE TABLE2 ....
    END;

-- Only needed if you also need to call this elsewhere, e.g. from AdHoc Sql
CREATE PROC dbo.OuterTransactional
  AS
    BEGIN
      BEGIN TRY
        BEGIN TRAN
            EXEC dbo.InnerNonTransactional
        COMMIT TRAN
      END TRY
      BEGIN CATCH
         -- Rollback and handling code here.
      END CATCH
    END;
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

在 SQL Server 2014 中使用带有事务的存储过程的 TransactionScope 的相关文章

  • 我们可以在 C# 中定义枚举的隐式转换吗?

    是否可以在 C 中定义枚举的隐式转换 可以实现这一目标的东西吗 public enum MyEnum one 1 two 2 MyEnum number MyEnum one long i number 如果没有 为什么不呢 有一个解决方案
  • 您使用什么工具和技术来查找死代码? [关闭]

    Closed 这个问题正在寻求书籍 工具 软件库等的推荐 不满足堆栈溢出指南 help closed questions 目前不接受答案 您使用哪些工具和技术来查找 NET 中的死代码 过去 我用 Obsolete 属性修饰方法 传递 tr
  • 在 2 个 .c 文件之间共享函数

    dir1有dir2 file1 c和file1 h dir2 有 file2 c 现在 如果我想在 file2 c 中访问 file1 c 中定义的函数 我需要在 file1 h 中声明它并在 file2 c 中包含 file1 h 这是一
  • 带方括号的 Uri.EscapeUriString

    这是一个奇怪的问题 但让我们看看它会得到什么样的回应 如果我编写一个控制台应用程序 VS 2013 NET 4 5 1 并执行这行代码 Uri EscapeUriString 我明白了 但是 如果我执行同样的事情 嗯 从技术上来说Uri E
  • 在子目录中构建共享库

    我正在尝试构建一个使用一些 C 代码的 R 包 我有一个编译为可执行文件的 C 库 可以从命令行调用 有一个与之关联的 Makefile 我正在尝试获取信息here http cran r project org doc manuals R
  • 如何将 CroppedBitmap 转换为 BitmapImage

    我正在尝试将 CroppedBitmap 转换为 BitmapImage 编辑 不使用内存流 我尝试过直接转换它 似乎这不是一个选择 这应该没那么难 我正在尝试剪切 BitmapImage 的一部分 并创建一个仅包含新裁剪的 Bitmap
  • 错误 C2065:'cout':未声明的标识符

    我正在处理我的编程作业的 驱动程序 部分 但我不断收到这个荒谬的错误 错误 C2065 cout 未声明的标识符 我什至尝试过使用std cout但我收到另一个错误 IntelliSense 命名空间 std 没有成员 cout 当我宣布u
  • 如何将 QSerialPort 模块添加到 CMake 中?

    我想将 QSerialPort 模块添加到 CMake 中 根据我的理解 我需要将QT 串口添加到 pro中 我只想使用 CMake 所以我尝试编译简单的 CMake 文件 但有错误 QtCore 正在工作 qDebug 可以毫无问题地显示
  • 测试从 ComboBox 派生的自定义控件

    我创建了一个从 ComboBox 派生的控件 并希望对其行为进行单元测试 但是 它在我的单元测试中的行为似乎与实际应用程序中的行为不同 在实际应用程序中 Combobox DataSource 属性和 Items 同步 换句话说 当我更改
  • Linux C++ 调试器

    我正在寻找完美的 Linux C 调试器 我不期望成功 但搜索应该提供丰富的信息 我是一个非常有能力的 gdb 用户 但 STL 和 Boost 很容易压垮我的调试技能 并不是说我无法深入了解数据结构的内部结构 而是它需要很长时间 我通常会
  • Excel 2007 中的数值 - 底层 xml 文件中的表示与存储

    这个问题与 NET和OpenXml有关 我已经阅读了以下文章 它有很好的解释 但没有回答我的问题 Excel 2007 中数值的可视化与底层 xml 文件不一致 https stackoverflow com questions 58594
  • 使用非管理员帐户时,SQL Linked Server 返回错误“不存在登录映射”

    我有一个本地 SQL Server 2008R2 我已将链接服务器配置为远程数据库 当我使用 SQL 登录帐户登录本地服务器时 链接服务器工作得很好sysadmin服务器角色 我可以查询远程服务器 因此我知道链接服务器设置是正确的 但是 如
  • 简单的喷射器将具体类型与生活方式结合起来

    我正在寻找一种可以使用指定的生活方式注册具体类型的方法 基本上如下所示 public void SomeFunction Type concrete Lifestyle lifestyle gt container Register con
  • 链接错误:xxx 已在 *****.LIB 中定义:: 究竟出了什么问题?

    Problem 我正在尝试使用一个名为DCMTK http dicom offis de dcmtk它使用了一些其他外部库 zlib libtiff libpng libxml2 libiconv 我已经从同一网站下载了这些外部库 LIB
  • 在 C# 中为 ListBox 分配数据源时,如何从 ListBox 中删除所选项目?

    在 C 中为 ListBox 分配数据源时 如何从 ListBox 中删除所选项目 尝试删除时出现错误 设置 DataSource 属性后 无法修改项目集合 但是当我尝试从数据源 数据表 中删除项目时 它会抛出错误 因为 数据行不在当前行集
  • 矩阵行列式算法 C++

    我是编程新手 我一直在寻找一种找到矩阵行列式的方法 我在网上找到了这段代码 但我很难理解这里的算法 我对递归的基础没有问题 但继续和主循环我很难理解 非常感谢任何可以向我解释该算法的人 int determ int a MAX MAX in
  • 使用反射检测属性的访问修饰符类型

    我编写了一些代码来使用反射查看属性 我已经使用反射从类中检索了属性列表 但是我需要查明该财产是公共的还是受保护的 例如 public string Name get set protected int Age get set Propert
  • 预览MouseMove 与 MouseMove

    我有相当多的 XAML 经验 但最近我注意到我的大多数同事都使用预览鼠标移动代替鼠标移动事件 我一直用鼠标移动它对我很有帮助 但我忍不住问我什么时候应该使用预览鼠标移动什么时候鼠标移动 有什么区别 各自有什么优点和缺点等等 PreviewM
  • 从不同的线程访问对象

    我有一个服务器类 它基本上等待来自客户端的连接 在该类中 我创建了一个 NetworkStream 对象 以便能够从客户端接收字节 由于 NetworkStream Read 方法不是异步的 这意味着它将等到从客户端读取字节才能继续执行类似
  • Python - 将列表作为参数传递给 SQL,以及更多变量

    我试图在 python 3 6 中将未知数量的参数传递给 SQL Server 这是我使用 pypyodbc 的代码 cursor cnxn cursor theargs 1033286869 1053474957 1063654630 1

随机推荐

  • 需要在 Coldfusion 9 上运行 JPA + Hibernate java 项目的建议

    我有一个使用 JPA 2 Hibernate 3 5 6 进行数据访问的 java 项目 它在 JBoss 应用程序服务器上运行得很好 现在我尝试在 Coldfusion 9 环境上运行它 我看到 CF 9 已经有了 hibernate3
  • 将记录与另一个表上的最新记录连接

    我正在尝试创建一个 SQL 视图 我如何从一个表中选择最新的记录 而其他记录保持原样 我需要从所有表中选择所有记录 这工作正常 但我需要仅按日期选择最新的提案 这是我遇到的问题 这是我到目前为止所拥有的 SELECT TOP 100 PER
  • 在 JavaScript(而非 JQuery)中自动设置电话号码格式

    我发现以下代码用于在 JavaScript 中格式化电话号码这篇文章来自堆栈溢出 https stackoverflow com questions 45471788 formatting the phone number for mult
  • 如何用python从客户端向服务器发送消息

    我正在阅读带有客户端和服务器的 Python 2 7 10 中的两个程序 如何修改这些程序以便从客户端向服务器发送消息 服务器 py usr bin python This is server py file import socket I
  • 后退按钮不会导致回发到 MVC 中的控制器操作

    当我在 Win7 上的 IE10 或 Chrome 中单击后退按钮时 它不会到达 MVC 控制器中的断点 IE 开发者工具中的 网络 选项卡显示 304 未修改 并且 Fiddler 未捕获该请求 我期待着回帖 这样我就可以在我的控制器中工
  • IHttpModule 和控制台应用程序的流畅 NHibernate 模式

    我目前有一个在存储库模式中使用 Fluent NHibernate LINQ 的 C MVC 2 Web 应用程序 并使用 Ninject 来处理 MVC 控制器的构造函数要求 将其传递到存储库中 我的 Fluent NHibernate
  • 即使单击“允许”后,也会出现“执行该操作需要授权”消息

    我最近遇到了一个授权新的 Google App Script 项目的问题 特别是使用 Cloud SQL 管理 API 的项目 相同的代码存在于之前授权的 GAS 项目中并且工作正常 但是如果我获取 GAS 项目的副本并尝试第一次运行某个函
  • 如何只处理某些 XML 节点?

    这是我的 XML 片段 它有一个根元素
  • 手风琴内的 ui bootstrap datepicker 不可见

    我正在尝试在手风琴内制作一个带有日期选择器的模块 问题是日期选择器弹出框在手风琴上不可见 这是一个显示问题的笨蛋 http plnkr co edit jBqU0LXQFcUuzQLency2 p preview http plnkr co
  • 为什么这段代码不交换数字? [复制]

    这个问题在这里已经有答案了 可能的重复 为什么这些交换函数的行为不同 https stackoverflow com questions 4330929 why do these swap functions behave differen
  • 如何消除错误 3002?

    假设我在 SQL Server 2008 中有以下表定义 CREATE TABLE Person PersonId INT IDENTITY NOT NULL PRIMARY KEY Name VARCHAR 50 NOT NULL Man
  • Mongoose 在结果的 _id 字段中返回“new ObjectId”

    当我尝试查询时 结果包含 id其中包含 new ObjectId 的字段 如何避免这种 new ObjectId 并仅将哈希值包含为字符串 由于此问题 将数据作为 JSON 响应发送回失败 下面是一个基本的demo 我的查询代码 book
  • 从 google 地图 api 隐藏本地列表

    当使用谷歌地图 API 显示某些内容时 谷歌已开始将当地餐馆 酒店添加到地图中 我怎样才能隐藏它们不出现 我在使用地图的网站 例如 yelp 上检查了相同的位置 他们成功地隐藏了当地的酒店 餐厅 我一直在寻找图层 叠加层 但无法弄清楚如何删
  • 仅选择一半记录

    我试图弄清楚如何选择 ID 为空的一半记录 我想要一半 因为我将使用该结果集来更新另一个 ID 字段 然后我将使用该 ID 字段的另一个值更新其余部分 所以本质上我想用一个数字更新一半记录 someFieldID 用另一个数字更新其余记录
  • Angular UI Grid - 将图像导出为 pdf

    我想将图像添加到 pdf 的标题中 我正在尝试添加已转换为 base64 的图像以导出 Pdf 标题 scope gmGrid exporterPdfHeader margin 30 5 30 15 table widths body MC
  • 如何根据值复制Azure数据工厂中的数据?

    我的问题是这样的 例如 我有一个包含三列的表 其中 SQL Server table1 id number1 number2 和 other table2 id finalNumber 我怎样才能进行有条件复制 我想复制 table2 fi
  • 禁用“未找到匹配项”文本并在 select2 上自动完成

    如何在 select2 Tagging 支持的自动完成功能上禁用 未找到匹配项 文本 这就是我现在所拥有的 ProductDescriptions 30 keywords select2 tags tokenSeparators minim
  • Safari 中的按钮是否损坏?

    我有一些带有单行文本的按钮 我们称它们为short 我还有其他带有多行文本的按钮 我们称它们为long 在 Chrome 中 所有按钮看起来都很好并且相同 但在 Safari 中 long看起来不同于short long看起来像是被压住了
  • 不同大小组的高效递归随机抽样

    这个问题是我之前关于递归随机抽样问题的后续问题高效的递归随机采样 https stackoverflow com questions 69824065 efficient recursive random sampling 当组大小相同或每
  • 在 SQL Server 2014 中使用带有事务的存储过程的 TransactionScope

    我正在使用 C 和 ADO NetTransactionScope在 ASP Net 应用程序中运行事务 该事务应该在多个表中保存一些数据 然后向订阅者发送电子邮件 Question 是否有效使用TransactionScope 当它包含对