zoukankan      html  css  js  c++  java
  • Linq 事务

    事务是一个原子的工作单位,必须完整的完成单位里的所有工作,要么全部执行,要么全部都不执行。如果提交事务,则事务执行成功;如果回滚事务,则事务执行失败。 事务具备4个基本特性--ACID(原子性、一致性、孤立性和持久性)。

      在Linq to SQL中,有三种方法创建事务:

    1.  如果没有指定任何事务,那么当调用SubmitChanges方法时,DataContext会默认创建一个事务。
    2. 使用TransactionScope创建轻量级事务
    3. 给DataContext的Transaction属性指定事务 

    下面我用代码分别来说明这几种创建事务的方法,以Northwind数据库为例,先来看看直接使用SubmitChanges:

     NorthwindDataContext ctx = new NorthwindDataContext();
    
     Customer c1 = new Customer { CustomerID = "TESTA", CompanyName = "testa's company" };
     Customer c2 = new Customer { CustomerID = "TESTBC", CompanyName = "testb's company" };
    
     ctx.Customers.Add(c1);
     ctx.Customers.Add(c2);
    
     ctx.SubmitChanges();
    

    上面这段代码中,先创建了两个Customer对象然后添加到DataContext里面,其中的c2的CustomerID赋值为"TESTBC",长度为六个字符,而数据库中该字段约束为5个字符长度,这样在SubmitChanges的时候应该会有异常抛出。果然在执行的时候抛出了SqlException,提示字符将被截断。

    image

    再通过Sql Server管理器可以看到上面这两条数据都没有被插入到数据库中。通过Reflector可以发现在SubmitChanges的时候,Linq to SQL默认创建了一个孤立级别为Read Committed的事务(它表示已提交的更新在事务间是可见的,具体有哪些孤立级别可以参考ADO.NET相关资料):

     public virtual void SubmitChanges(ConflictMode failureMode)
     {
         ...
         transaction = this.provider.Connection.BeginTransaction(IsolationLevel.ReadCommitted);
         this.provider.Transaction = transaction;
    
     }
    如果不想使用默认的事务设置,比如想改变事务的孤立级别,我们可以给DataContext的Transaction属性赋值,以此使用自定义的事务。
      ctx.Transaction = ctx.Connection.BeginTransaction(System.Data.IsolationLevel.Serializable);
      try
      {
          ctx.SubmitChanges();
          ctx.Transaction.Commit();
      }
      catch
      {
          ctx.Transaction.Rollback();
          throw;
      }
      finally
      {
          ctx.Transaction = null;
      }
    

    最后一种方式是通过TransactionScope创建轻量级事务,就像在ADO.NET中使用一样:

     using (TransactionScope scope = new TransactionScope())
     {
         ctx.SubmitChanges();
         scope.Complete();
    
     }
    

    上面的例子看起来似乎多此一举,因为在SubmitChanges中会创建默认的事务,但是改成下面这样,就只能使用自定义的事务了:

     using (TransactionScope scope = new TransactionScope())
     {
         ctx.ExecuteCommand("exec ....");
         ctx.ExecuteCommand("exec ....");
         ctx.ExecuteCommand("exec ....");
         ctx.SubmitChanges();
         scope.Complete();
    
     }
    

    不管ExecuteCommand里面执行了哪些操作,我们都能够指明这些行为和SubmitChanges处于同一个事务中。

    -----------------------------------------------------------------------------------------------------------

    另外,附上我自己实现的 自定义事务,该事务是轻量级,不会像 TransactionScope那样可能会涉及分布式(DTC)事务:

    try
    {
        if (dbContext.Connection.State == System.Data.ConnectionState.Closed)
        {
            dbContext.Connection.Open();
        }
    
        /*
            为了兼顾那些非EF操作,即采用直接拼Sql作数据库访问时,数据库链接需作一点转换:
            cmd.Connection = (dbContext.Connection.BeginTransaction as EntityConnection).StoreConnection;
         */
        using (DbTransaction ts = dbContext.Connection.BeginTransaction())
        {
            page.SortID = 0;
            page.IsDeleted = false;
            dbContext.B_SystemPage.AddObject(page);
            dbContext.SaveChanges();
            ts.Commit();
            message = "添加成功!";
        }
        return true;
    }
    catch
    {
        message = "添加失败!";
        return false;
    }
    finally
    {
        if (dbContext.Connection.State == System.Data.ConnectionState.Open)
        {
            dbContext.Connection.Close();
        }
    }

    若干操作隶属一个事务的本质是它们基于同一个连接,所以自己对 Connection对象作了全方面管理,比如

    dbContext.Connection.Open();

    再由这个链接启动事务:

    using (DbTransaction ts = dbContext.Connection.BeginTransaction())
    {
    }
  • 相关阅读:
    【第五年-创业路】
    【工具与解决方案】从做项目中积累学习
    【原理篇】人工智能
    【原理】分布式系统
    攻克Spring
    工具篇集锦
    最好用的JQuery插件集合以及组合拳
    设计模式 之状态模式
    设计模式 之组合模式
    设计模式之 封装算法
  • 原文地址:https://www.cnblogs.com/luoxiaonet/p/2371432.html
Copyright © 2011-2022 走看看