ADO.NET中的TransactionScope何时需要启用MSTDC(分布式事务管理)
我们知道在ADO.NET中可以用TransactionScope来将多个SqlConnection(多个数据库连接)执行的Sql语句放入一个事物中提交或取消,但是使用TransactionScope的时候也要额外小心,因为TransactionScope在特殊情况下需要启动MSDTC(分布式事务管理)服务,那么我们来看看什么时候TransactionScope需要启动MSDTC呢?
首先来声明下本例中代码和数据库的环境,首先本例使用的数据库是SqlServer 2008 R2,本例中C#代码运行的电脑和SqlServer数据库所在的电脑是局域网中的两个机器,也就是说ADO.NET所在的程序和SqlServer是在两台电脑上,为什么要强调这个问题呢?因为我查阅文章发现ADO.NET所在的程序和SqlServer部署在一台电脑,和部署在两台电脑上,TransactionScope的行为还不太一样,这个也和SqlServer的版本有关系,后面会有总结。
我们先来看一个例子,在下面的ADO.NET客户端程序代码中我们使用TransactionScope启动了两个SqlConnection,这两个SqlConnection使用的连接字符串都相同,而此时我们的ADO.NET客户端程序所在的电脑是没有启动MSDTC的,所以如果TransactionScope需要启动MSDTC那么下面这段代码就会抛出异常。
protected const string connectionString = @"Data Source=192.168.1.3;Initial Catalog=Mobile_Reporting_DM_Staging;Persist Security Info=True;User ID=sa;Password=0okm9ijn*UHB&YGV"; static void Main(string[] args)
{
string sql = string.Empty;
SqlCommand sqlCom; using (TransactionScope tran = new TransactionScope(TransactionScopeOption.RequiresNew))
{
using (SqlConnection sqlCon1 = new SqlConnection(connectionString))
{
sqlCon1.Open(); sql = "insert into [dbo].[T_People](Name,age) values(N'王刚',20)"; sqlCom = new SqlCommand(sql, sqlCon1);
sqlCom.ExecuteNonQuery();
} using (SqlConnection sqlCon2 = new SqlConnection(connectionString))
{
sqlCon2.Open(); sql = "insert into [dbo].[T_People](Name,age) values(N'李强',30)"; sqlCom = new SqlCommand(sql, sqlCon2);
sqlCom.ExecuteNonQuery();
} tran.Complete();
} Console.ReadLine();
}
而执行上面这段代码后我们发现程序并没有出现异常,而且两个SqlConnection都成功地向数据库中插入了一条数据,这说明上面这段代码TransactionScope并没有用到MSDTC服务。这说明如果TransactionScope中启动的多个SqlConnection(多个数据库连接)连接的同一个SqlServer实例的相同数据库,那么TransactionScope是不会用到MSDTC服务的。
然后我们将上面的代码做一下修改,定义两个连接字符串connectionString1和connectionString2,分别指向同一个SqlServer实例的不同数据库,其中connectionString1指向了数据库Mobile_Reporting_DM_Staging,而connectionString2指向了数据库Mobile_Reporting_DM,那么这一次TransactionScope中的两个SqlConnection会分别连接同一个SqlServer实例的不同数据库,我们执行下面的代码看会发生什么呢?
protected const string connectionString1 = @"Data Source=192.168.1.3;Initial Catalog=Mobile_Reporting_DM_Staging;Persist Security Info=True;User ID=sa;Password=0okm9ijn*UHB&YGV";
protected const string connectionString2 = @"Data Source=192.168.1.3;Initial Catalog=Mobile_Reporting_DM;Persist Security Info=True;User ID=sa;Password=0okm9ijn*UHB&YGV"; static void Main(string[] args)
{
string sql = string.Empty;
SqlCommand sqlCom; using (TransactionScope tran = new TransactionScope(TransactionScopeOption.RequiresNew))
{
using (SqlConnection sqlCon1 = new SqlConnection(connectionString1))
{
sqlCon1.Open(); sql = "insert into [dbo].[T_People](Name,age) values(N'王刚',20)"; sqlCom = new SqlCommand(sql, sqlCon1);
sqlCom.ExecuteNonQuery();
} using (SqlConnection sqlCon2 = new SqlConnection(connectionString2))
{
sqlCon2.Open(); sql = "insert into [dbo].[T_People](Name,age) values(N'李强',30)"; sqlCom = new SqlCommand(sql, sqlCon2);
sqlCom.ExecuteNonQuery();
} tran.Complete();
} Console.ReadLine();
}
执行上面代码后我们发现在代码第23行sqlCon2.Open()抛出了异常,异常提示"该伙伴事务管理器已经禁止了它对远程/网络事务的支持。 (异常来自 HRESULT:0x8004D025)",这句话的意思就是TransactionScope需要用到MSDTC(分布式事务管理)服务,但是操作系统的MSDTC服务并没有启动。
所以我们看到当我们要求TransactionScope中启动的多个SqlConnection(多个数据库连接)连接同一个SqlServer实例的不同数据库时,TransactionScope就需要启动MSDTC(分布式事务管理)服务了。这与我预先的理解有很大的不同,我以前一直以为只有当TransactionScope中的多个SqlConnection(多个数据库连接)连接不同的SqlServer实例时才需要MSDTC,但是事实证明当TransactionScope中的SqlConnection连接同一个SqlServer实例的不同数据库时就需要MSDTC了。
下面我们来总结下TransactionScope什么时候需要启动MSDTC(以下结论都是基于SqlServer2008及其后续版本的,SqlServer2005在后面会有特殊说明)
- 不管你ADO.NET程序所在的服务器和数据库服务器是同一台电脑或不同的电脑,只要TransactionScope中的多个SqlConnection(多个数据库连接)连接的是同一个SqlServer实例的相同数据库时,TransactionScope不需要MSDTC(分布式事务管理)服务
- 不管你ADO.NET程序所在的服务器和数据库服务器是同一台电脑或不同的电脑,只要TransactionScope中有多个SqlConnection(多个数据库连接)连接同一个SqlServer实例的不同数据库时,TransactionScope就需要启用MSDTC(分布式事务管理)服务
- 不管你ADO.NET程序所在的服务器和数据库服务器是同一台电脑或不同的电脑,只要TransactionScope中的多个SqlConnection(多个数据库连接)连接不同的SqlServer实例时,TransactionScope需要启用MSDTC(分布式事务管理)服务
- 如果你ADO.NET程序所在的服务器和数据库服务器是同一台电脑,TransactionScope将不支持环回链接服务器,因为SqlServer的分布式事务本来就不支持环回链接服务器,环回链接服务器的解释请看这里。
- 不管你ADO.NET程序所在的服务器和数据库服务器是同一台电脑或不同的电脑,只要TransactionScope中有SqlConnection(数据库连接)执行的Sql语句使用到了LinkedServer(链接服务器),那么TransactionScope就需要启用MSDTC(分布式事务管理)服务,不光是TransactionScope,实际上只要SqlServer的事务中用到了LinkedServer(链接服务器),那么SqlServer就会启动分布式事务从而用到MSDTC服务
所以我们可以看到在不同的应用场景下TransactionScope的行为是不一样的。另外关于上面第二点,其实可以使用变通的方法来避免TransactionScope启用MSDTC,如果数据库A和数据库B位于同一个SqlServer实例,那么我们可以让TransactionScope中的多个SqlConnection(多个数据库连接)都连接到数据库A,但是在Sql语句中使用[数据库B].[Schema].[表名]这种带数据库前缀的完全限定名来操作数据库B的数据,这样TransactionScope是不会用到MSDTC的。
这里要特别强调下SqlServer2005及其之前的版本,实际上SqlServer2005及其之前的版本对TransactionScope的支持力度非常差,我们发现数据库是SqlServer2005时,只要ADO.NET程序所在的服务器和数据库服务器不是同一台电脑,TransactionScope就需要启用MSDTC(分布式事务管理)服务,即便在TransactionScope中只使用了一个SqlConnection发起唯一的一个数据库连接,TransactionScope都要求启用MSDTC。所以当数据库是SqlServer2005时,只有当ADO.NET程序所在的服务器和数据库服务器是同一台电脑,并且TransactionScope中的多个SqlConnection(多个数据库连接)连接的是同一个SqlServer实例的相同数据库时,TransactionScope才不需要MSDTC(分布式事务管理)服务。
此外关于MSDTC(分布式事务管理)服务在这里多说一句,分布式事务要求在ADO.NET客户端程序所在的服务器和数据库服务器上同时启用MSDTC才能正常工作,而单方面只启动ADO.NET客户端程序所在的服务器上的MSDTC或只启动数据库服务器上的MSDTC是不行的。因为分布式事务实际上是通过不同服务器间的MSDTC服务来提交的,所以涉及到分布式事务的所有服务器都必须要启用MSDTC服务后,分布式事务才可以正常工作。
另外本文的很多观点借鉴了下面这篇博客的内容,大家可以参考下,也感谢这位博主的对TransactionScope的研究和分享。
ADO.NET中的TransactionScope何时需要启用MSTDC(分布式事务管理)的更多相关文章
- 已禁用对分布式事务管理器(MSDTC)的网络访问。请使用组件服务管理工具启用 DTC 以便在 MSDTC 安全配置中进行网络访问。
今天写ASP.NET程序,在网页后台的c#代码里写了个事务,事务内部对一张表进行批量插入,对另外一张表进行查询与批量插入. 结果第二张表查询后foreach迭代操作时报错:已禁用对分布式事务管理器(M ...
- 关于分布式事务的一个误解:使用了TransactionScope就一定会开启分布式事务吗?
背景: 事务是数据库管理系统的一个基本概念,事务具有四个基本特点,即ACID:原子性(Atomicity).一致性(Consistency).隔离性(Isolation)和持久性(Durability ...
- 事务使用中如何避免误用分布式事务(System.Transactions.TransactionScope)
1:本地事务DbTransaction和分布式事务TransactionScope的区别: 1.1:System.Data.Common.DbTransaction: 本地事务:这个没什么好说了,就是 ...
- 如何避免误用分布式事务(System.Transactions.TransactionScope)
以下内容来源与:http://www.cyqdata.com/cyq1162/article-detail-54453 1:本地事务DbTransaction和分布式事务TransactionScop ...
- C#中分布式事务的超时处理问题
事务是个很精妙的存在,我们在数据层.服务层.业务逻辑层等多处地方都会使用到. 在这里我只说下TransactionScope这个微软推荐使用的隐式事务.它是从Framework 2.0开始引入的一个事 ...
- 将不确定变为确定~transactionscope何时提升为分布式事务~SQL2005与SQL2008不同
回到目录 Transactionscope何时被提升为分布式事务,即时要触发msdtc服务,这个问题与数据库版本有关,在前面的文章中,我的MSTDC系列出现了多个版本,有一点没有说清楚,测试的环境不同 ...
- J2EE分布式事务中的提交、回滚方法调用异常。
这个是昨天上班的时候,写一个后台程序的调试程序时碰到的问题,和项目经理纠结了一天,最后搞定了.于是今天上班正好闲着,花了几乎一天的时间去网上找各种相关的资料.目前了解的内容如此: 根据使用的weblo ...
- 关于spring中事务管理的几件小事
1.Spring中的事务管理 作为企业级应用程序框架,Spring在不同的事务管理API之上定义了一个抽象层.而应用程序开发人员不必了解底层的事务管理API,就可以使用Spring的事务管理机制. S ...
- Spring中的事务管理详解
在这里主要介绍Spring对事务管理的一些理论知识,实战方面参考上一篇博文: http://www.cnblogs.com/longshiyVip/p/5061547.html 1. 事务简介: 事务 ...
随机推荐
- Android笔记:百度地图与高德地图坐标转换问题
安卓项目使用了百度地图的定位SDK,web端使用的也是百度地图, 后来发现界面显示百度地图不如高德效果好,web改用高德地图,原本的百度地图坐标是可以直接使用的,由于高德和百度地图的坐标系不一致 要如 ...
- python入门 2014-3-21
刚吃完饭,写一会python 准备去上课,哇咔咔! 1.python是动态类型语言,也就是说 不需要预先声明变量的类型. 不支持 自增++ , 自减--
- Java学习-003-JDK、JRE、JVM简介
此文主要对 JDK.JRE.JVM进行简单的介绍,给各位亲们一个参考.若有不足之处,敬请各位大神指正,不胜感激! 一.基本概念 JDK(Java Development Kit:Java 开发工具包) ...
- hexo 搭建博客
使用hexo搭建网站.记录一下. hexo搭建方法: https://wsgzao.github.io/post/hexo-guide/ http://jacob110.github.io/2015/ ...
- Xcode编译错误和警告汇总<转>
1.error: macro names must be identifiers YourProject_prefix.pch 原因: 因为你弄脏了预处理器宏,在它处于<Multiple Val ...
- 关闭不安全的HTTP方法
关闭不安全的HTTP方法 在项目或tomcat下的web.xml中,添加如下配置: <!-- 关闭不安全的HTTP方法 --> <security-constraint> &l ...
- Cache封装类
代码: using System; using System.Collections.Generic; using System.Linq; using System.Text; using Syst ...
- [SharpMap]二叉树索引
读取shp文件建立二叉树索引的基本思路分析: /// <summary> /// Generates a spatial index for a specified shape file. ...
- MongoDB固定集合
固定集合 MongoDB 固定集合(Capped Collections)是性能出色且有着固定大小的集合,对于大小固定,我们可以想象其就像一个环形队列,当集合空间用完后,再插入的元素就会覆盖最初始的头 ...
- nodejs weixin 笔记
http://www.oschina.net/code/snippet_218887_25870 好文章: http://codelife.me/blog/2013/04/23/developing- ...