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. 事务简介: 事务 ...
随机推荐
- Surround the Trees---hdu1392(凸包GraHam模板)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1392 题意:有n棵树,每棵树有一个坐标,想用一些绳子把这些树包含起来,求需要绳子的长度: 就是求凸包的 ...
- Java学习-026-类名或方法名应用之二 -- 统计分析基础
前文讲述了类名或方法的应用之一调试源码,具体请参阅:Java学习-025-类名或方法名应用之一 -- 调试源码 此文主要讲述类名或方法应用之二统计分析,通过在各个方法中插桩(调用桩方法),获取方法的调 ...
- 01 viewport
<meta name="viewport" content="width=device-width,initial-scale=1.0">
- Java ConcurrentHashMap
通过分析Hashtable就知道,synchronized是针对整张Hash表的,即每次锁住整张表让线程独占, ConcurrentHashMap允许多个修改操作并发进行,其关键在于使用了锁分离技术. ...
- VMWare ESXi 5.5安装及配置
VMWare ESXi 5.5安装大概过程如下:制作虚拟化ESXi系统的USB启动盘,安装ESXi系统到USB,用USB启动ESXi系统.比较难理解,下面图解过程. 下载UNetbootin (下 ...
- 微信的公众号unionid
此外,由于开发者经常有需在多个平台(移动应用.网站.公众帐号)之间共通用户帐号,统一帐号体系的需求,微信开放平台(open.weixin.qq.com)提供了UnionID机制.开发者可通过OpenI ...
- NET4.5之初识async与await
这是两个关键字,用于异步编程.我们传统的异步编程方式一般是Thread.ThreadPool.BeginXXX.EndXXX等等.把调用.回调分开来,代码的逻辑是有跳跃的,于是会导致思路不是很清晰的问 ...
- DTMF Stresstesting
import threading,time,serial,sys from random import randrange port_snd=14 port_recv=2 recnt=0 ser_ ...
- PHYLIP linux安装
PHYLIP的安装: http://download.chinaunix.net/download.php?id=29483&ResourceID=8135下载 gunzip phylip-3 ...
- M面经prepare: Shuffle a deck
设计一个shuffle card 用了java. Random Class package Random; import java.util.*; public class Solution { st ...