以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 普遍,但有时也要使用。一般都是SqlDataAdapter的Update 方法的时候需要回滚,方法如下:
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();
}
}