两种实现事务方法的比较

引言

提到事务,大部分人都知道数据库和Com+中有事务性,其实在.net framework中,还提供了一种集成了Ado.Net和SQL Server common language runtime (CLR)的方法,采用System.Transactions.TransactionScope也能实现数据访问的事务性。

本文目的

通过阅读本文,您可以了解以下知识

  1. 向您介绍一种新的实现事务的方式
  2. System.Transactions.TransactionScope的应用场合
  3. 和数据库事务比较,二者在性能上的差距

向您介绍一种新的实现事务的方式

.Net Frameworl 2.0为我们新增了命名空间,System.Transactions,这个命名空间为我们提供了一种新的实现事务的方案,它能组织一系列的代码,如果不执行Complete方法,这些被组织的代码的执行将无效。

Msdn给出的实例为:  

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

        
// Do work in the first connection.

        
// Assumes conditional logic in place where the second
        
// connection will only be opened as needed.
        using (SqlConnection connection2 = new 
            SqlConnection(connectString2))
        
{
            
// Open the second connection, which enlists the 
            
// second connection and promotes the transaction to
            
// a full distributed transaction. 
            connection2.Open();

            
// Do work in the second connection.
        }

    }

    
//  The Complete method commits the transaction.
    transScope.Complete();
}

 

System.Transactions.TransactionScope的应用场合

传统的数据库事物有一定的弊端,比如下面这种这种情形:

User和MemberShip是父子类的关系,且各自有各自的实现,User类也是实现类,非抽象类,而数据库中数据表设计如下:

那么在实现Add方法的时候,特别是MemberShip的Add方法如何保证User和UserDetail两个数据表操作的事务性呢?

当然我们可以使用两个不同的SQL,用SqlTransaction来保证事务性,但MemberShip的Add代码是不是就有重复的地方呢,这样的实现看起来怎么也不美观,因为子类并没有享受到父类给与的恩赐。那么使用System.Transactions.TransactionScope便可以解决这个问题,我们可以先实现User.Add(),因为MemberShip继承于User,当实现MemberShip的Add方法时,便可以如下做

 public override bool Add()
        
{
            
bool pRes = false;
            
using (System.Transactions.TransactionScope tx = new System.Transactions.TransactionScope())
            
{
                
//这个首先调用服务的添加方法,填充数据表Users
                pRes = base.Add();
                
//下面可以实现向UserDetail中添加数据
                  
                
if(都成功了)
                
{
                    
//提交,相当于Commit
                    tx.Complete();
                }


            }
         
            
return pRes;
        }


这样的实现,显得会 更OO一些。

和数据库事务比较,二者在性能上的差距

既然有些场合是适合使用System.Transactions.TransactionScope的,那他的性能如何呢?自己做了一个简单的测试,得出下面的测试数据

循环次数

SqlTransaction

TransactionScope

性能比

100

442183162

15016030072

33.95

100

361575387

4891560000

13.52

100

403243350

4857052275

12.04

1000

3675252488

17089946707

4.65

1000

4078101240

17229690090

4.22

1000

3589697130

19112327573

5.32

10000

46847708078

119662532843

2.55

10000

45370373625

112767966525

2.48

从上面的测试结果可以看出System.Transactions.TransactionScope的性能比SqlTransaction要低,大概在10倍之内。

测试项目文件

测试项目: /Files/jillzhang/TxCompare.rar

数据库文件: /Files/jillzhang/db.rar

 

作者:jillzhang
出处:http://jillzhang.cnblogs.com/
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
Tag标签: 事务
posted @ 2008-02-20 15:18 Robin Zhang 阅读(3995) 评论(40)  编辑 收藏 网摘 所属分类: .net framework

  回复  引用    
#1楼2008-02-20 15:29 | laoda[未注册用户]
这东西具有不确定性 ,ms没有说它在什麽环境下用,我用的时候就出现了不起作用的情况,搞不清楚该怎么解决只好放弃使用。
  回复  引用  查看    
#2楼[楼主]2008-02-20 15:42 | jillzhang      
在我的测试中,用在数据库操作还没发现出现不管用的情况
  回复  引用  查看    
#3楼2008-02-20 15:47 | 代码乱了      
不知道对其他的数据操作的场景是不是适应
  回复  引用  查看    
#4楼[楼主]2008-02-20 15:59 | jillzhang      
System.Transactions 基础结构通过支持在 SQL Server、ADO.NET、MSMQ 和 Microsoft 分布式事务协调器 (MSDTC) 中启动的事务,使事务编程在整个平台上变得简单和高效。
  回复  引用  查看    
#5楼[楼主]2008-02-20 15:59 | jillzhang      
@代码乱了
不知道对其他的数据操作的场景是不是适应
------------------------------------
其他数据,比如变量赋值,这些是不行的

  回复  引用  查看    
#6楼2008-02-20 16:00 | Wenly      
这个东西用的时候有时会出现奇怪的故障,跟1楼想法一样.所以放弃使用了.比如你数据库和应用服务器不是同一台的时候就会出问题.
  回复  引用  查看    
#7楼2008-02-20 16:01 | yuuhhe      
误人子弟
不要拿数据库事务做例子

  回复  引用  查看    
#8楼2008-02-20 16:02 | Wenly      
还有一个事务里面只能出现一次sqlConnection 连接
  回复  引用  查看    
#9楼[楼主]2008-02-20 16:03 | jillzhang      
@yuuhhe
那应该用什么做例子呢?

  回复  引用  查看    
#10楼[楼主]2008-02-20 16:04 | jillzhang      
@Wenly
看msdn给的代码
using (TransactionScope transScope = new TransactionScope())
{
using (SqlConnection connection1 = new
SqlConnection(connectString1))
{
// Opening connection1 automatically enlists it in the
// TransactionScope as a lightweight transaction.
connection1.Open();

// Do work in the first connection.

// Assumes conditional logic in place where the second
// connection will only be opened as needed.
using (SqlConnection connection2 = new
SqlConnection(connectString2))
{
// Open the second connection, which enlists the
// second connection and promotes the transaction to
// a full distributed transaction.
connection2.Open();

// Do work in the second connection.
}
}
// The Complete method commits the transaction.
transScope.Complete();
}
应该不限于一个连接吧

  回复  引用  查看    
#11楼2008-02-20 16:09 | Wenly      
@jillzhang
是的,我也是看了.那是数据库和应用服务器是同一台的时候不会出错。但是当数据库和应用服务器不在同一台时就会出现问题.不过感谢LZ给了我们做的性能分析,受益了.

  回复  引用  查看    
#12楼2008-02-20 16:12 | yuuhhe      
你把系统服务中的msdtc禁用掉再试试看还能运行吗
  回复  引用  查看    
#13楼2008-02-20 16:13 | 第一控制.NET      
需要msdtc
  回复  引用  查看    
#14楼2008-02-20 16:17 | Wenly      
@yuuhhe
呵呵,是这样的吗?我安装msdtc弄了好久都没解决.我想了好多办法,最后还是老老实实用以前的事务处理了.可能自己技术还没到火候吧.我想应该不是msdtc这个的问题,我只要一换成一个sqlConnection连接就行了.不过我看到老外是这样解决的http://www.cnblogs.com/weck0736/archive/2007/11/24/971303.html总觉得太麻烦,放弃了

  回复  引用  查看    
#15楼2008-02-20 16:21 | Tristan(Guozhijian)      
sql的事务我还是选择用sql transaction.

这个东西用于一些io操作的事务处理应该比较好。

  回复  引用  查看    
#16楼2008-02-20 16:24 | yuuhhe      
在TransactionScope中执行Connection.Open()就会调用COM+的分布式事务
服务没有开会自动开,禁用掉会出错。服务器客户端都要求开分布式事务,在XP和2003中基于安全的原因会关闭网络dtc,在2003上安装IIS时会看到这个选项。即使启用了网络dtc,还需要主机间的互相验证,不同机器开不了就是这个原因,如果两台机器都加入一个域中是能通过主机验证的,如果都是独立主机那就要配置组件服务了。在组件服务-〉我的电脑上按右键选属性,在MSDTC选项卡中点安全性配置,所有东西都在[安全设置]这里了。如果安装IIS时选择启用了网络dtc访问,那么在你看到的[安全设置]里[网络DTC访问]是打上钩了的,如果是两台独立主机选择[不要求进行验证]就可以使用了。

  回复  引用  查看    
#17楼[楼主]2008-02-20 16:28 | jillzhang      
http://www.cnblogs.com/cn_wpf/archive/2007/08/06/844766.html" target="_new">http://www.cnblogs.com/cn_wpf/archive/2007/08/06/844766.html
这个有解决分布式事务解决方案,基本和yuuhhe说的差不多

  回复  引用  查看    
#18楼[楼主]2008-02-20 16:31 | jillzhang      
vs2008中也有System.Transactions,回家测试一下,是否还有这样的问题
多谢@yuuhhe
@Wenly
@第一控制.NET

  回复  引用  查看    
#19楼[楼主]2008-02-20 16:33 | jillzhang      
跳出数据库操作,我觉得在父子类继承的处理上,System.Transactions也大有用途
  回复  引用  查看    
#20楼2008-02-20 16:56 | yuuhhe      
过两天我发一个改过的DAAB,我改了下那里的TransactionScopeConnection,让它只开Connection事务
  回复  引用  查看    
#21楼2008-02-20 16:59 | yuuhhe      
TransactionScope只是一个思想,配合using语句很好用,在2003的时候我就没爱弄,因为我们只用VB.net -_-!
  回复  引用  查看    
#22楼2008-02-20 17:07 | yuuhhe      
你说的父子类继承的处理,其实是TransactionScope构造函数的默认参数的实现,也是个思想而已
  回复  引用  查看    
#23楼[楼主]2008-02-20 17:12 | jillzhang      
@yuuhhe
看来你对TransactionScope研究的比较透彻,多谢指点。

  回复  引用  查看    
#24楼2008-02-20 17:13 | PerfectDesign      
如果仅仅从你的举例来看,直接使用begin transation 是最好的选择。
我相信transactionscope应该还可以管理其他的事务,比如文件的读写webservice等

  回复  引用  查看    
#25楼[楼主]2008-02-20 17:25 | jillzhang      
@PerfectDesign
那如何体现Add方法的继承关系呢?

  回复  引用  查看    
#26楼[楼主]2008-02-20 17:30 | jillzhang      
begin transation
效率是高
但如果用它,子类是不是就不能从父类获得好处呢?

  回复  引用  查看    
#27楼2008-02-20 20:40 | PerfectDesign      
两个方法分别开连接调用会增加sql连接的负担
不过开发速度可以加快。
只是矛和盾的问题,不过我喜欢封装在DB里。

本来可以在一个sp里实现的,被拆开在2次会话中执行,并且增加了事务的距离,并发不是很好了。

  回复  引用  查看    
#28楼2008-02-20 22:49 | 马可香蕉      
transactionscope在存在两个sqlConnection 是会有问题,我做昨天刚好做过测试
  回复  引用    
#29楼2008-02-21 03:03 | saucer[未注册用户]
如果有2个或以上的连接对象,就会跃迁为OleTx式事务,很明显,overhead就大了,但如果你设置你的DbUitily.ExecuteSql重用一个SqlConnection对象的话,你就会发现性能就差不多了
  回复  引用  查看    
#30楼2008-02-21 08:31 | BlackCat      
@jillzhang
@Wenly
@yuuhhe

我最近在做一个项目的时候,突然间,所有带有事务处理的com+组件都不能正常工作了,错误信息是:"dtc不能进行通信" . 过来经过努力,我们的解决方案是,在本地连接中,TCP/IP协议的高级里,WINS设置添加了服务器的IP,之后又关闭了防火墙,才可以进行正常工作,但是他们并没有给出原因和为什么这么解决,我一直想搞清楚,这个问题到底应该怎么解决??

  回复  引用  查看    
#31楼2008-02-21 08:32 | BlackCat      
我主要想知道为什么??这个问题应该怎么解决??
  回复  引用  查看    
#32楼[楼主]2008-02-21 09:12 | jillzhang      
@BlackCat
DTC采用RPC动态分配的端口号进行通讯,端口分配机制会随机选选取1024以上的端口,如果中间有防火墙,那开放的端口号就很难确定,所以你关闭防火墙就起到了让通讯双方Host能够彼此端口到达,
----------以上解释了为和要关闭防火墙-------------
例外DTC的工作依赖于NetBIOS或者DNS解析机器名,通讯双方必须能互相ping通对方的机器名才行,而wins(Windows Internet Name Service -windows网际名称服务)正是为NetBIOS名字提供名字注册、更新、释放和转换服务,所以设置wins可使双方主机满足互相ping通主机名的要求

  回复  引用  查看    
#33楼[楼主]2008-02-21 09:13 | jillzhang      
另外,如果你不想关掉防火墙,在RPC端口分配机制上是可以通过修改注册表来实现固定端口的,具体方法参见
http://support.microsoft.com/default.aspx?scid=kb;en-us;250367" target="_new">http://support.microsoft.com/default.aspx?scid=kb;en-us;250367

  回复  引用  查看    
#34楼2008-02-21 21:51 | yuuhhe      
楼上正解,可以配置成只分配一个固定端口给RPC,多台应用服务器可以通过这一个端口建立DTC连接,我配成功过,但只限于单纯数据库服务器,没有在域控制器或Exchange服务器等也需要RPC的服务器上验证过,所以要小心的设置RPC分配端口
  回复  引用  查看    
#35楼2008-02-22 13:28 | BlackCat      
@jillzhang
@yuuhhe
好的,谢谢大家,知道了.

  回复  引用  查看    
#36楼2008-02-22 15:58 | 毁于随      
以前做过一次,应用环境是在两个不同的主机的数据库之间使用分布式事务,结果出现很多莫名其妙的问题,后来放弃了。
  回复  引用  查看    
#37楼2008-07-23 20:51 | BAsil      
受教了,不错



发表评论

昵称: [登录] [注册]

主页:

邮箱:(仅博主可见)

评论内容:

  登录  注册

[使用Ctrl+Enter键快速提交评论]

0 1075057




相关文章:

相关链接: