天天@BLOG

脖子越来越疼,脑袋越来越钝
  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

DotNet使用事务的方法

Posted on 2005-12-22 09:54  天天在线  阅读(333)  评论(0编辑  收藏  举报

       数据库的操作比较复杂,特别是插入等操作难免有错误,为了保证数据的完整性,在数据库操作中常常需要使用事务。通过事物来完成一组操作,一旦其中出现任何错误,可以回滚这一组操作,这样数据就不会因为操作中的某个失误而变得不完整。

         SQL SERVERADO.NET为例,数据库中操作数据库比较多的是使用两种方法,一个是 通过SqlCommand对象,另一种是SqlDataAdapter对象,下面分别介绍这两种情况下使用事务的方法。

一、使用SqlCommand操作数据库时候使用事务

因为使用起来比较方便,所以这种方法是使用比较多的方法,代码如下:

 

SqlConnection conn = new SqlConnection(ConnectString);//定义一个SqlConnection
conn.Open();
SqlTransaction trans 
= conn.BeginTransaction();//获得conn的TranSaction
//定义一组操作Command
SqlCommand cmd1 = new SqlCommand();
SqlCommand cmd2 
= new SqlCommand();
//设置command的属性
cmd1.Connection = conn;
cmd1.CommandText 
= cmdText;
cmd.Transaction 
= trans;

cmd2.Connection 
= conn;
cmd2.CommandText 
= cmdText;
cmd2.Transaction 
= trans;
//操作
try
{
cmd1.ExecuteNonQuery();
cmd2.ExecuteNonQuery();

trans.Commit();                  
}


//如果出现错误,回滚操作
catch {
trans.Rollback();
throw;
}

 

二、使用SqlDataAdapter操作数据库时候使用事务

       SqlDataAdapter的操作使用事务不如SqlCommand 普遍,但有时也要使用。一般都是SqlDataAdapterUpdate 方法的时候需要回滚,方法如下:

 

public bool Update(DataSet ds,string strSql,SqlTransaction theTrans,SqlConnection conn)
public bool Update(DataSet ds,string strSql,SqlTransaction theTrans,SqlConnection conn)
{
    SqlDataAdapter sda 
= new SqlDataAdapter(strSql,conn);
    
//使用命令生成器生成Command
    SqlCommandBuilder scb = new SqlCommandBuilder(sda);
    sda.SelectCommand.Transaction 
= theTrans;
    
//使用事务
    sda.DeleteCommand.Transaction = theTrans;
    sda.UpdateCommand.Transaction 
= theTrans;
    sda.InsertCommand.Transaction 
= theTrans;
        dsCommand.Update(data);
    
if ( data.HasErrors )
              
{
                   data.Tables[
0].GetErrors()[0].ClearErrors();
                   
return false;
              }

              
else
              
{
                   data.AcceptChanges();
                   
return true;
          }
 
}

 

调用事务

 

SqlTransaction theTrans = conn.BeginTransaction(IsolationLevel.Serializable);
try{
theobject.Update(data,sqlStr,theTrans,conn);
theTrans.Commit(IsolationLevel.ReadCommitted);
}

catch
{
theTrans.RollBack();
throw;
}

 

三、使用COM+的事务功能

       在分层设计的系统中,以上两种方法都应该在数据层的内部完成,而使用系统Com+的事务功能则可以把事务放到高层中进行,这样操作起来更加灵活。不过按照系统分层的原则,数据层的事情最好不要放到其他层中进行,所以除非必要,这种处理方式应该尽量避免。

       EnterpriseServices.ServicedComponent继承类

       先添加引用System.EnterpristServices

 

namespace xxx
{
using System;
using System.Reflection;
using System.Runtime.InteropServices;       
using System.EnterpriseServices;  
[Transaction(System.EnterpriseServices.TransactionOption.Required)]
//指定事务类型
[ClassInterface(ClassInterfaceType.AutoDispatch)] //指定要生成的类的接口类型
[ObjectPooling(MinPoolSize=4, MaxPoolSize=4)] //指定对象池
public class MyBusiness : ServicedComponent {
protected override bool CanBePooled() {
           
return true
          }

[AutoComplete]   
//标记为自动完成方法
public int  InsertData(DataSet ds)
{}
     }
 
     }
 
}

 

 

       上面的类中的InsertData方法就是一个完整的事务,方法中的操作可以保持完整性,可以把一组数据操作放在这儿执行。这种操作不是单独对数据库适用,只是数据库操作也可以使用这种方法来完成一组事务,而且对多个数据库的同步来说,这是比较好的一种选择。

四、  使用SeviceConfig来完成事务

       对比上面的ServicedComponent来说,使用SeviceConfig比较方便。使用ServicedComponent的程序集需要强名称,而且这个程序集所引用的程序集也必须是强名称。当然不是说强名称不好,但很多人有时候在发布前的开发调试阶段可能把这一步就先空着,等到发布的时候再加上强名称。还有,似乎在Web程序使用自己开发的Com+总是有些问题,不知道哪儿配置错了,反正我现在就是这样,每次修改都需要用regsvcs/u 把程序集发注册掉,然后重新生成程序集,再使用regsvcs 注册,然后用gacutil/i 添加到 GAC(Global Assembly Cache),不然的话使用SevicedComponent派生出来的类就有问题。好了,现在终于可以不用ServicedComponent了,可以使用SeviceConfig了,SeviceConfig的好处就是可以使用Service但是又不需要把它绑定到组件中去。但是,别高兴太早,一个不幸的消息就是SeviceConfig只能在Windows 2003下面使用,除非你保证自己开发的程序只运行在Windows2003平台下,否则你还是老老实实的使用前面几种方法吧。闲言少叙,我们还是来看看怎么用吧。

 

using System.EnterpriseServices;
public class  MyClass
{
         ServiceConfig config 
= new ServiceConfig(); 
         config.Transaction 
= TransactionOption.Required; 
         ServiceDomain.Enter(config);
         
try
         
{
              
// 需要事务处理的代码
               ContextUtil.SetComplete();
         }

         
catch(Exception e)
         
{
            ContextUtil.SetAbort();
         }

         
finally
         
{
            ServiceDomain.Leave(); 
        }

}
@忙碌,不代表有效率;方法,远胜于苦干