热烈祝贺台州朗动科技的站长论坛隆重上线!(2012-05-28)    热烈庆祝伟大的祖国60周年生日 点击进来我们一起为她祝福吧(2009-09-26)    站长论坛禁止发布广告,一经发现立即删除。谢谢各位合作!.(2009-08-08)    热烈祝贺台州网址导航全面升级,全新版本上线!希望各位一如既往地支持台州网址导航的发展.(2009-03-28)    台州站长论坛恭祝各位新年快乐,牛年行大运!(2009-01-24)    台州Link正式更名为台州网址导航,专业做以台州网址为主的网址导航!(2008-05-23)    热烈祝贺台州Link资讯改名为中国站长资讯!希望在以后日子里得到大家的大力支持和帮助!(2008-04-10)    热烈祝贺台州Link论坛改名为台州站长论坛!希望大家继续支持和鼓励!(2008-04-10)    台州站长论坛原[社会琐碎]版块更名为[生活百科]版块!(2007-09-05)    特此通知:新台州站长论坛的数据信息全部升级成功!">特此通知:新台州站长论坛的数据信息全部升级成功!(2007-09-01)    台州站长论坛对未通过验证的会员进行合理的清除,请您谅解(2007-08-30)    台州网址导航|上网导航诚邀世界各地的网站友情链接和友谊联盟,共同引领网站导航、前进!(2007-08-30)    禁止发广告之类的帖,已发现立即删除!(2007-08-30)    希望各位上传与下载有用资源和最新信息(2007-08-30)    热烈祝贺台州站长论坛全面升级成功,全新上线!(2007-08-30)    
便民网址导航,轻松网上冲浪。
台州维博网络专业开发网站门户平台系统
您当前的位置: 首页 » ASP/ASP.NET编程 » 谈谈 .NET2.0中避免分布式事务

谈谈 .NET2.0中避免分布式事务

论坛链接
  • 谈谈 .NET2.0中避免分布式事务
  • 发布时间:2007-09-21 16:39:26    浏览数:7178    发布者:abcdef133    设置字体【   
.NET Framework 2.0 版中新增的 TransactionScope 单独使用确实很方便。但是在实际项目中都有自己的访问层,如何才能和自己的数据访问层结合起来使用呢?

  在项目中我是这样处理数据的:


/**//// <summary>
/// 外包业务访问类
/// </summary>
public class OutSourcingDAO
{

/**//// <summary>
/// 增加
/// </summary>
/// <param name="bt"></param>
/// <returns></returns>
public int InsertGetIdentity(OutSourcing bt)
{
 return new DAHelper(DataAccess.Create()).InsertGetIdentity(bt);
}
/**//// <summary>
/// 更新
/// </summary>
/// <param name="bt"></param>
/// <returns></returns>
public int Update(OutSourcing bt)
{
 return new DAHelper(DataAccess.Create()).Update(bt);
}
/**//// <summary>
/// 删除
/// </summary>
/// <param name="bt"></param>
/// <returns></returns>
public int Delete(OutSourcing bt)
{
 return new DAHelper(DataAccess.Create()).Delete(bt);
}
}

  上面 OutSourcing 为与表相对应的实体类 ;DAHelper 为作者自己实现的一个包装类,可以对任意实体进行增加,修改,删除 查询等功能。
再贴一段代码:


public int ExecSql(string strSql)
{
 try
 {
  this.OpenConnection();
  cmd.CommandType = CommandType.Text;
  cmd.CommandText = strSql;

  return cmd.ExecuteNonQuery();
 }
 catch (System.Exception e)
 {
  throw this.CatchException(e);
 }
 finally
 {
  this.CloseConnection();
 }
}

  我最终通过调用 ExecSql 方法来与数据库交互,而该方法会自己打开数据库连接,执行语句,然后关闭连接。
在操作同一个数据库的时候,如果要高效的使用 TransactionScope,必须保证 SqlConnection 不改变,即用同一个 SqlConnection 来完成所需要的增加删除,或修改。我想写这样的代码进行事务控制:


public int UpdateTest(OutSourcing outSourcing, BusinessAccept businessAccept)
{
 IDataAccess dac = DataAccess.Create();
 DAHelper myHelper = new DAHelper(dac);
 using (TransactionScope ts = new TransactionScope())
 {
  myHelper.Update(outSourcing);
  myHelper.Update(businessAccept);

  ts.Complete();
 }
}

  这样就需要,执行第一个操作时候打开数据库连接,执行,不关闭连接,然后执行第二个操作,执行完关闭。显然,我想让 TransactionScope 在 实行 Dispose() 方法的时候关闭数据库连接。using 代码块的本质上等同于 try{}finally{} 语句代码块。为什么不封装一下 TransactionScope 让它满足自己的要求呢?


/**//// <summary>
/// TransactionScope 包装类
/// </summary>
public sealed class Scope : IDisposable
{
 private TransactionScope m_TransactionScope = null;
 /**//// <summary>
 /// 测试访问类
 /// </summary>
 private DataAccessTest m_DataAccessTest = null;
 /**//// <summary>
 /// 实例化一个新的 TransactionScope
 /// </summary>
 /// <param name="dac"></param>
 public Scope(DataAccessTest dac)
 {
  this.m_DataAccessTest = dac;
  //告诉访问类 你已经使用了事务
  dac.SetScope(this);
  this.m_TransactionScope = new TransactionScope();
 }
 /**//// <summary>
 /// 发出事务结束命令
 /// </summary>
 public void Complete()
 {
  this.m_TransactionScope.Complete();
 }
 IDisposable 成员#region IDisposable 成员
 /**//// <summary>
 /// 当执行该方法的时候完成两件任务
 /// 1 关闭数据库栀湩???? ??魀?(连接
 /// 2 调用 TransactionScope 的 Dispose()方法
 /// </summary>
 void IDisposable.Dispose()
 {
  try
  {
   m_DataAccessTest.Close();
  }
  finally
  {
   m_TransactionScope.Dispose();
  }
 }

 #endregion
}

  数据库访问类代码如下:


/**//// <summary>
/// 模拟数据库访问类
/// </summary>
public class DataAccessTest
{
 SqlConnection con = null;
 SqlCommand cmd = new SqlCommand();
 Scope scope = null;
 string strCon = "这里是数据库连接字符串。。。。。";

 public void SetScope(Scope scope)
 {
  this.scope = scope;
 }
 private void OpenConnection()
 {
  if (con == null || scope == null)
  {
   con = new SqlConnection(strCon);
   cmd.Connection = con;
   con.Open();
   Console.WriteLine(" 打开数据库连接;");
  }
 }

 private void CloseConnection()
 {
  this.cmd.Parameters.Clear();
  if (scope == null)
  {
   //
   con.Close();
   con.Dispose();
   Console.WriteLine(" 未使用事务 关闭数据库连接;");
  }
 }

 public int ExecuteSql(string strSql)
 {
  try
  {
   this.OpenConnection();
   cmd.CommandType = CommandType.Text;
   cmd.CommandText = strSql;
   Console.WriteLine("执行 Sql 语句。。。");

   return cmd.ExecuteNonQuery();
  }
  catch (System.Exception e)
  {
   throw e;
  }
  finally
  {
   this.CloseConnection();
  }
 }

 public void Close()
 {
  con.Close();
  con.Dispose();
  Console.WriteLine(" 关闭数据库连接->该方法由 Scope中的Dispose()方法调用 ");
 }
}
       赶快写个方法测试一下吧!


/**//// <summary>
/// 测试
/// </summary>
/// <param name="sender">
/// <param name="e"></param>
private void button1_Click(object sender, EventArgs e)
{
 try
 {
  Console.WriteLine("下面是使用事务的输出......");
  this.TestACT();
  Console.WriteLine("*********************下面是 未 使用事务的输出");
  this.TestNoACT();
 }
 catch (System.Exception ex)
 {
  Console.WriteLine("出现了异常????????????");
  MessageBox.Show(ex.ToString());
 }

}
/**//// <summary>
/// 使用事务
/// </summary>
public void TestACT()
{
 DataAccessTest dac = new DataAccessTest();
 using (Scope scope = new Scope(dac))
 {
  string strSql1 = "INSERT INTO [tilva20].[dbo].[T_Test]([TestName])VALUES('a')";
  string strSql2 = "INSERT INTO [tilva20].[dbo].[T_Test]([TestName])VALUES('b')";
  dac.ExecuteSql(strSql1);
  dac.ExecuteSql(strSql2);

  scope.Complete();
 }
}
/**//// <summary>
/// 不使用事务
/// </summary>
public void TestNoACT()
{
 DataAccessTest dac = new DataAccessTest();

 string strSql1 = "INSERT INTO [tilva20].[dbo].[T_Test]([TestName])VALUES('a')";
 string strSql2 = "INSERT INTO [tilva20].[dbo].[T_Test]([TestName])VALUES('b')";
 dac.ExecuteSql(strSql1);
 dac.ExecuteSql(strSql2);
}

  查看一下输入的结果。

  下面是使用事务的输出。

  打开数据库连接;

  执行 Sql 语句。 

  关闭数据库连接->该方法由 Scope中的Dispose()方法调用

  *********************下面是 未 使用事务的输出

  打开数据库连接;

  执行 Sql 语句。

  未使用事务

  关闭数据库连接;

  打开数据库连接;

  执行 Sql 语句。

  未使用事务

  关闭数据库连接;

  输出结果和想像中的完全一样 数据库也正确(没任何原因不正确!)

  最后 改变一下方法:


/**//// <summary>
/// 使用事务
/// </summary>
public void TestACT()
{
 DataAccessTest dac = new DataAccessTest();
 using (Scope scope = new Scope(dac))
 {
  string strSql1 = "INSERT INTO [tilva20].[dbo].[T_Test]([TestName])VALUES('a')";
  string strSql2 = "INSERT INTO   [tilva20].[dbo].[T_Test]([TestName])VALUES('b222222222
22222222222222222222222222222222222222222222222222222222222222222222222222222')";
  dac.ExecuteSql(strSql1);
  dac.ExecuteSql(strSql2);

  scope.Complete();
 }
}

  熟悉数据库的肯定知道 “将截断字符串或二进制数据”吧!

  输出结果为:

  下面是使用事务的输出。

  打开数据库连接;

  执行 Sql 语句。

  关闭数据库连接->该方法由 Scope中的Dispose()方法调用

  出现了异常?

  数据库一条记录没有增加 数据库连接已经关闭 测试结果完全满意!

  对自己访问层稍做修改:

  最终的代码为:


public int UpdateTest(OutSourcing outSourcing, BusinessAccept businessAccept)
{
 IDataAccess dac = DataAccess.Create();
 DAHelper myHelper = new DAHelper(dac);
 using (Scope ts=new Scope())
 {
  myHelper.Update(outSourcing);
  myHelper.Update(businessAccept);

  ts.Complete();
 }
}
娱乐休闲专区A 影视预告B 音乐咖啡C 英语阶梯D 生活百科
网页编程专区E AMPZF HTMLG CSSH JSI ASPJ PHPK JSPL MySQLM AJAX
Linux技术区 N 系统管理O 服务器架设P 网络/硬件Q 编程序开发R 内核/嵌入
管理中心专区S 发布网址T 版主议事U 事务处理