享受代码,享受人生

SOA is an integration solution. SOA is message oriented first.
The Key character of SOA is loosely coupled. SOA is enriched
by creating composite apps.
posts - 219, comments - 2359, trackbacks - 162, articles - 45
  博客园 :: 首页 :: 新随笔 :: 联系 :: 订阅 订阅 :: 管理

Transaction in ADO.net 2.0

Posted on 2005-08-15 20:28 idior 阅读(10159) 评论(14)  编辑 收藏 网摘 所属分类: Windbey

 在谈具体实现前 先介绍一下三种事务:
1. 单对象单资源

2. 多对象单资源


3. 多对象多资源(分布式事务, 使用两段提交协议)


在ADO.Net1.0下有两种使用Transaction的方法. 一种是在需要事务的对象中显式的调用事务处理, 还有一种是使用Enterprise Service的声明式的方法.

第一种方法的示例代码如下:

      public void TransactionTest()
        
{
            
string connectionString = "";
            IDbConnection connection 
= new SqlConnection(connectionString);
            connection.Open();
            IDbCommand command 
= new SqlCommand();
            command.Connection 
= connection;
            IDbTransaction transaction;
            transaction 
= connection.BeginTransaction(); //Enlisting database
            command.Transaction = transaction;
            
try
            
{
                
/* Interact with database here, then commit the transaction
                
*/

                transaction.Commit();
            }

            
catch
            
{
                transaction.Rollback(); 
//Abort transaction
            }

            
finally
            
{
                connection.Close();
            }

        }

这种方法使用起来相当麻烦, 而且只能针对一个对象访问一个资源的事务. 如果事务涉及多个对象,那么由谁来进行事务处理?  如果事务使用了多个资源, 那样又涉及到分布式事务和两段提交协议,此时依靠第一种方法完全由用户自己控制实在过于复杂,因此在提供了第一种基本方法后, ADO.Net 1.0又利用Com+实现了声明式的事务处理,示例代码如下:

using System.EnterpriseServices;
[Transaction]
public class MyComponent : ServicedComponent
{
[AutoComplete]
public void MyMethod()
{
/*Interact with other serviced components
and resource managers 
*/

}

}

这种声明式的方法看上去似乎很好,但是也隐含了许多问题.
1. 使用事务的对象需要继承ServicedComponent
2. 即使不涉及多资源的分布式事务而仅仅是涉及到了多个对象的简单事务(开头介绍的第二种事务),我也要使用此方法,影响了效率. 这样的弊端和J2ee中的都在本地的Entity Bean之间进行通讯很像,杀鸡也不得不用牛刀.
3. 不可避免的使用了Com+.
4. 使用Enterprise Services的事务总是线程安全的, 也就是说你无法让多个线程参与到同一个事务中.

ADO.Net2.0 提供的新的事务模型综合了前两者的优点,
1 在简单(不涉及分布式)事务中也可以使用声明式的事务处理方法, 而不必使用Com+容器, ADO.net 2.0中提供了一个轻量级的事务容器.
2 用户根本不需要考虑是简单事务还是分布式事务. 新模型会自动根据事务中涉及的对象资源判断使用何种事务管理器. 简而言之, 对于任何的事务用户只要使用同一种方法进行处理. 示例代码:

using(TransactionScope scope = new TransactionScope())
{
/* Perform transactional work here */
//No errors - commit transaction
scope.Complete();
}

另外对嵌套事务和事务的隔离级别也提供了支持, 在此就不作详细介绍. Fantasy Soft对此做了介绍.

using(TransactionScope scope1 = new TransactionScope())
//Default is Required
{
using(TransactionScope scope2 = new 
TransactionScope(TransactionScopeOption.Required))
{}
using(TransactionScope scope3 = new 
TransactionScope(TransactionScopeOption.RequiresNew))
{}
using(TransactionScope scope4 = new 
TransactionScope(TransactionScopeOption.Suppress))
{}

}




TransactionOptions options = new TransactionOptions();
options.IsolationLevel 
= IsolationLevel.ReadCommitted;
options.Timeout 
= TransactionManager.DefaultTimeout;
using(TransactionScope scope = new TransactionScope(TransactionScopeOption.Required, options))

 

public enum IsolationLevel
{
ReadUncommitted,
ReadCommitted,
RepeatableRead,
Serializable,
Unspecified,
Chaos, 
//No isolation whatsoever
Snapshot //Special form of read committed 8
supported by SQL Server 2005
}

本文仅仅是ADO.net 2.0 Transaction的简单介绍, 详细资料查看M$的相关文档.

参考资料:  Introducing System.Transactions  by Juval Lowy  
 

1
0
(请您对文章做出评价)
« 上一篇:Rhino Mocks (RhinoMock)2
» 下一篇:Visitor模式全解

Feedback

#1楼   回复  引用  查看    

2005-08-16 09:06 by James      
good

#2楼   回复  引用  查看    

2005-08-16 10:56 by tongling      
上个项目使用了Com+事务处理,使用起来是比较方便,就是效率极差.hehe
那时虽然知道2.0提供了轻量级的transaction模型,但公司一直在用1.0没有升级,所以... 其实小型的项目可以把transaction全部放在SP里面,效率高。

#3楼   回复  引用  查看    

2005-08-21 14:39 by Flier Lu      
TransactionScope 这种细粒度事务管理,实际上是由 Win2003 的 COM+ 1.5 提供支持,跟 .NET 1.0/2.0 版本无关。回头有空我整个 .NET 1.1 的实现出来,这个特性是 COM+ 1.5 里面最重要的特性之一了。至于 trans 性能不高,主要是用 COM+ 后系统缺省通过 DTC 来完成事务协调,而在本地非两段事务处理中,这样的损耗是没有必要的。

#4楼[楼主]   回复  引用  查看    

2005-08-21 20:05 by idior      
---
TransactionScope 这种细粒度事务管理,实际上是由 Win2003 的 COM+ 1.5 提供支持,跟 .NET 1.0/2.0 版本无关。
---

没错, 不过那个轻量的容器应该是2.0提供的吧.
其实关键在于用户不需要考虑是分布式还是本地的事务, 统一使用TransactionScope 的申明式事务,这才让TransactionScope 更加有意义, 而这点应该是ado.net2.0才实现的功能.

#5楼   回复  引用    

2005-12-24 09:50 by loke[未注册用户]
想看更多的文章

#6楼   回复  引用  查看    

2006-04-17 18:23 by 皇帝的新装      
对分布式的事务处理有没有实验过?

#7楼   回复  引用    

2006-04-17 18:31 by idior,[未注册用户]
@皇帝的新装
这个功能绝对没有问题.

#8楼   回复  引用  查看    

2006-05-26 22:35 by 锋锋      
.NET1.1的版本.
// ?2005 IDesign Inc. All rights reserved
//Questions? Comments? go to
//http://www.idesign.net

using System;
using System.EnterpriseServices;

public enum TransactionScopeOption
{
Suppress = TransactionOption.NotSupported,
Required = TransactionOption.Required,
RequiresNew = TransactionOption.RequiresNew
}

public class TransactionScope : IDisposable
{
bool m_Consistent = false;

public void Complete()
{
if(m_Consistent == false)
{
m_Consistent = true;
}
else
{
throw new InvalidOperationException("Cannot call Complete() more than once");
}
}
public TransactionScope() : this(TransactionScopeOption.Required)
{}

public TransactionScope(TransactionScopeOption scopeOption)
{
ServiceConfig config = new ServiceConfig();
config.Transaction = (TransactionOption)scopeOption;
ServiceDomain.Enter(config);
}
public void Dispose()
{
if(m_Consistent == false && ContextUtil.IsInTransaction)
{
ContextUtil.MyTransactionVote = TransactionVote.Abort;
}
ServiceDomain.Leave();
m_Consistent = false;
}
}


#9楼   回复  引用  查看    

2006-05-26 22:37 by 锋锋      
using (TransactionScope ts = new TransactionScope())
{
//....
}

#10楼   回复  引用  查看    

2006-11-27 13:15 by avisnet      
在你说的“多对象单资源”中使用TranscationScope会使用分布式事务吗?

#11楼   回复  引用    

2007-02-15 12:46 by edwin[未注册用户]
你好,我想请教一下,在同一个事务中是否可以实现对同一张表Table的同一个字段a进行重复GetMax()和UpdateNum()。


IDbConnection connection = null;
IDbTransaction transaction = null;
try
{
Database db = DBAccess.GetDBInstance();
connection = db.GetConnection();
connection.Open();
transaction = connection.BeginTransaction();

//取最大值
int GetMax():

//更新最大值
int num = GetMax();
UpdateNum(num);

.
.
.

//取最大值
int GetMax():

//更新最大值
int num = GetMax();
UpdateNum(num);

transaction.Commit();
}

int GetMax()
{
select Max(a)+ 1 from Table ;
return ;
}

int UpdateNum(num)
{
update Table set a = num ;
}

如果不可以,又有什么解决的方法呢?请赐教。

#12楼   回复  引用  查看    

2007-12-02 21:13 by 张荣华      
不错