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 studio配置AndroidAnnotations
现在很多人都使用Android studio开发工具代替eclipse了,当然的 在eclipse使用的好的一些开发框架也会对应的在android studio上面使用. 参考文档:http://bl ...
- URL Routing
们知道在ASP.NET Web Forms中,一个URL请求往往对应一个aspx页面,一个aspx页面就是一个物理文件,它包含对请求的处理. 而在ASP.NET MVC中,一个URL请求是由对应的一个 ...
- UIImage转换UIColor内存会莫名增大可以试试另一种方法
一般我们会用此方法加载被背景图片 [self.view setBackgroundColor:[UIColor colorWithPatternImage:[[UIImage alloc]initWi ...
- openni2 和opencv读取数据
http://blog.csdn.net/aptx704610875/article/details/49585241
- 第八篇 SQL Server安全数据加密
本篇文章是SQL Server安全系列的第八篇,详细内容请参考原文. Relational databases are used in an amazing variety of applicatio ...
- IIS 相关
Restart IIS: run "iisreset" command check port usage: netstat -ano How to set up SSL in II ...
- MSBUID相关(笔记)
用于创建可靠的最佳实践 Build,Part 1 http://msdn.microsoft.com/zh-cn/magazine/dd419659.aspx 用于创建可靠的最佳实践 Build,Pa ...
- rpmdb出问题,重建rpmdb库
1.备份原库 tar cvzf rpmdb-backup.tar.gz /var/lib/rpm 2.删除rpmdb库 rm -f /var/lib/rpm/__db.00* 3.重建库 rpm -- ...
- C# 统计程序执行时间
随便写写,小马哥勿怪 最近悟出来一个道理,在这儿分享给大家:学历代表你的过去,能力代表你的现在,学习代表你的将来. 十年河东十年河西,莫欺少年穷. 话说马云年轻的时候也是屌丝一枚,有图为证 现 ...
- EBS R12.2安装,使用的操作系统用户
在安装时,错误使用了oracle rdbms的对应的操作系统用户,导致安装前,验证时"web server install prerequisites"选项验证失败: (本图其它两 ...