在Entity framework中使用事务

默认情况下,当EF调用SaveChanges()时,会把生成的所有SQL命令“包”到一个“事务(transaction)”中,只要有一个数据更新操作失败,整个事务将回滚。
在多数情况下,如果你总在数据更新操作代码中使用一个而不是多个DbContext对象,并且只是在最后调用一次SaveChanges(),那么EF的默认事务处理机制己经够用了,无需做额外的事情。
然而,如果出现以下的情形,你就必须显式地处理事务了。


第一种情况:你需要分阶段地保存数据,因而需要多次调用SaveChanges()或者执行修改数据库的SQL命令。



请看以下示例代码:

using (var context = new MyDbContext())
{
    try
     {
        Person3 p = context.People3.First();

        p.Name ="newName" + (new Random().Next(1, 100));

        context.SaveChanges();

        context.Database.ExecuteSqlCommand("update Person3 setDescription={0} where Person3Id={1}",

                            "DescriptionModified at " + DateTime.Now.ToShortTimeString(),

                            p.Person3Id);
        p.age *= 2;
        context.SaveChanges();
    }
    catch (Exception e)
    {
        Console.WriteLine(e.Message);
    }
}

上述代码中,调用两次SaveChanges(),还有一次执行Update命令。
如果在最后一次SaveChanges()中出现异常,虽然最后一次没成功,但你会发现前两次数据己经保存!这就带来了数据不一致的问题。
对于这种场景,你需要显式地编写事务代码了(注:以下代码适用于EF6):

using (var context = new MyDbContext())
 {
    using (var transaction =context.Database.BeginTransaction())
    {
        try
        {
              ……
 
              context.SaveChanges();
 
              context.Database.ExecuteSqlCommand("……);
 
              ……
 
              context.SaveChanges();
              transaction.Commit();
 
         }
        catch (Exception e)
        {
               Console.WriteLine(e.Message);
               transaction.Rollback();
        }
    }
}

特别要注意一定要调用commit(),我测试发现,只要不Commit,即使没有异常发生,事务仍将回滚,数据库中的数据不会更新。

 

 

第二种情况,你需要使用多个DbContext保存数据,这种情况使用TransactionScope来提交事务


 

TransactionScope位于using System.Transactions;命名空间下,需要在引用中手动加入。该类不能被继承。

    //
    // 摘要:
    //     使代码块成为事务性代码。此类不能被继承。
    public sealed class TransactionScope : IDisposable

 

常用参数

  1. TransactionScopeOption
    //
    // 摘要:
    //     该范围需要一个事务。如果已经存在环境事务,则使用该环境事务。否则,在进入范围之前创建新的事务。这是默认值。
    Required = 0,
    
    //
    // 摘要:
    //     总是为该范围创建新事务。
    RequiresNew = 1,
    
    //
    // 摘要:
    //     环境事务上下文在创建范围时被取消。范围中的所有操作都在无环境事务上下文的情况下完成。
    Suppress = 2

     

  2. TimeSpan设置超时时间
            //
            // 摘要:
            //     以指定的超时时间值和要求初始化 System.Transactions.TransactionScope 类的新实例。
            //
            // 参数:
            //   scopeOption:
            //     System.Transactions.TransactionScopeOption 枚举的一个实例,描述与此事务范围关联的事务要求。
            //
            //   scopeTimeout:
            //     在 System.TimeSpan 之后,事务范围将超时并中止此事务。
            public TransactionScope(TransactionScopeOption scopeOption, TimeSpan scopeTimeout);

     

优点:

  1. 使用起来比较方便.TransactionScope可以实现隐式的事务,使你可以在写数据访问层代码的时候不用考虑到事务,而在业务层的控制事务.
  2. 可以实现分布式事务,比如跨库或MSMQ.
  3. 在EntityFramework中可以解决DbContextTransaction的多个上下文出现死锁问题。也就是说在EF中使用TransactionScope事务时,不用考虑数据库操作的多上下文问题。

缺点:

  1. 此种方式对于数据库锁定表,会影响其他进程的查询,也就是对于锁定的表,查询也锁定,不允许出现脏读,其他的查询需要挂起等待。重点是不能进行配置修改。
  2. 此种方式对于同一个范围/同一个逻辑操作,需要进行多线程的锁定处理,不然多个线程开启同一个事务会抛出异常。
  3. 多个事务操作中,存在锁定同一个表的时候也会出现死锁现象

使用实例如下:

Test1 _context = new Test1();
Test1 _context2 = new Test1();

using (TransactionScope tran = new TransactionScope())
{
    try
    {
        //1.修改省
        Area province = _context.Areas.FirstOrDefault(q => q.AreaLevel == 1);
        province.AreaName = province.AreaName + "1";
        _context.SaveChanges();
        Console.WriteLine(_context2.Areas.FirstOrDefault(q => q.AreaLevel == 1).AreaName);

        //2.修改市
        Area city = _context2.Areas.FirstOrDefault(q => q.AreaLevel == 2);
        city.AreaName = city.AreaName + "1";
        _context2.SaveChanges();

        //抛出异常
        throw new Exception("测试事务异常");
        tran.Complete();
    }

    catch (Exception ex)
    {
        Console.WriteLine("执行出错:" + ex.Message);
    }
}

从上面的代码我们可以看出来Entity Framework中,DbContex(_context和_context2)更新数据的数据库连接都是在调用SaveChanges方法时创建和关闭的,所以只要保证DbContex(_context和_context2)的SaveChanges方法都在TransactionScope的using代码块内调用,就可以保证DbContex(_context和_context2)更新数据的数据库连接都是在同一个事务中。

 

特别说明:
如果你的上下文(DbContext)在程序中只有一个,那么如果执行事务期间出现异常造成事务回滚,会出现数据模型和数据库中数据不对应情况,也就是说数据库的操作虽然被回滚了,但是EF中每个数据模型的状态却变成了事务成功提交后的了,但是实际上事务被回滚了。针对这个问题目前官方给的建议是,EF中如果事务回滚,就抛弃老的上下文(DbContext),使用一个新的上下文(DbContext)。

 

 

参考文献:

EntiryFramework中事务操作(二)TransactionScope

EntityFramework 事务处理

 

转载于:https://www.cnblogs.com/OpenCoder/p/9799586.html

57、Entity Framework 连接与事务的深入解析 本文深入解析了 Entity Framework 中的连接管理和事务处理机制。从显式和隐式连接控制,到事务使用场景及性能优化,全面探讨了如何高效地进行数据访问操作。同时,文章还总结了事务使用的最佳实践,并结合实战案例展示了事务在实际开发中的应用。通过本文,开发者可以更好地掌握 Entity Framework 的连接与事务管理,以提升系统性能和数据一致性。 阅读详情

相关推荐

Entity Framework 增 删 查 改 事务

使用Entity Framework数据库进行增、删、查、改、事务处理的代码示例。 开发工具为vs2013,EF6.0。 代码中使用了5个方法对标题上的5种操作进行了演示,简单明了的轻松使用EF。 希望对你有帮助!

Entity Framework事务

原文:Entity Framework事务 数据库事务 数据库事务(简称:事务)是数据库管理系统执行过程中的一个逻辑单位,由一个有限的数据库操作序列构成。事务允许以原子方式处理多个数据库操作。 如果已提交事务,则所有操作都会成功应用到数据库。 如果已回滚事务,则所有操作都不会应用到数据库数据库事务通常包含了一个序列的对数据库的读/写操作。包含有以下两个目的: 为数据库操作序列提供了一个...

VoldemortChi的博客 567

深入解析64B66B编码技术及其在高速接口中的同步模块实现

本文深入解析了64B66B编码技术,详细阐述了其相较于传统8B/10B编码在带宽利用率上的显著优势。文章重点探讨了该技术在高速接口中的核心实现,包括同步头、加扰机制,并提供了基于GT IP核的同步模块设计实战指南与调试经验,帮助工程师高效实现高速数据传输链路。

ll5678的博客 446

EF 6 DB-First系列--Entity Framework中的事务

在这您将了解EF 6 & EF Core中的事务。在Entity Framework中,SaveChanges()方法在内部创建一个事务,并将所有的INSERT、UPDATE和DELETE操作包装在其中。多个SaveChanges()调用,创建单独的事务,执行CRUD操作,然后提交每个事务。下面的示例演示了这一点。上面的示例将向控制台显示以下输出。在上面的示例中,我们将所有数据库命令记录到控制台。

a859745210b66a6的博客 454

Entity Framework事务 DbTransaction

public static void Transaction() { myitEntities entity = null; DbTransaction tran = null; try { entity = new myitEntities(); entity.Connection.Open(); tran = entity.Connect

tyfbhlxd的博客 936

Entity Framework事务处理

ef6之前,ef事务处理都是隐式处理的,从ef6开始可以手动显示进行处理了。需要明确的一点是:ef所有版本对select的操作除外,其他的增删改操作在执行savechanges()函数后均自动包装成事务处理的。 ...

知易行难的博客 319

Entity Framework使用事务

注需要添加DAL层对using System.Transactions的引用 在Entity Framework使用事务,将操作放在TransactionScope中,并通过Complete()方法提交事务即可。 示例代码如下: using (BlogDbContext context =new BlogDbContext()) { using (Transa

起风了 720

Entity Framework 6 主表和从表的事务插入方式

业务处理方式: 主表插入一条记录,取出主表的记录主键,赋值给予从表多条记录使用 微软的东西果然是一朝天子一朝臣,每代都不一样,找出的答案都不能解决问题,也许是我没找到吧。 自嘲下,记录这折腾了我两天的不满。 public void CreateWorkOrdGrid(Pp_WorkOrd_Hd headObject, List bodyObject) {

藏何的专栏 4315

Entity Framework中的事务

ef中的事务分为两种,隐式事务和显式事务, 隐式事务(一个上下文): //do something with context context.SaveChanges(); 这ef会创建一个隐式的事务,在context.SaveChanges();后,会自动调用commit命令,这是因为EF本身的操作是具有事务机制的 显示事务(多个上下文): using (TransactionS

Hello World 2143

Entity Framework Core事务深入剖析(高级开发必读篇)

掌握Entity Framework Core事务处理,有效解决数据一致性难题。涵盖手动提交、分布式事务及SaveChanges异步控制等核心方法,适用于高并发场景。提升数据库操作可靠性与性能,高级开发必读技巧,值得收藏。

InstrIsle的博客 603

Entity Framework应用:使用Code First模式管理事务

一、什么是事务 处理以数据为中心的应用时,另一个重要的话题是事务管理。ADO.NET为事务管理提供了一个非常干净和有效的API。因为EF运行在ADO.NET之上,所以EF可以使用ADO.NET的事务管理功能。 当从数据库角度谈论事务时,它意味着一系列操作被当作一个不可分割的操作。所有的操作要么全部成功,要么全部失败。事务的概念是...

csdnsunyf的专栏 190

Entity Framework Transaction事务 Code First、Database First、Model First

Entity Framework Core Entity Framework 6 Code First 数据注释 代码优先约定 查询数据 使用事务 ASP.NET Core MVC 和 EF Core - 教程系列比较 EF Core 和 EF6 1、数据注释Code First 数据注释 [Table("InternalBlogs")] public class B...

KingCruel的专栏 460

深入探索 Entity Framework Core:高效的数据访问与事务管理

EF Core 是一个ORM 框架,它通过将 C# 类与数据库表进行映射,让开发者在应用程序中使用对象,而非直接操作 SQL 语句。EF Core 的强大之处在于它不仅仅是一个简单的 ORM,还提供了性能优化、灵活的查询能力、自动迁移等功能,使得数据访问变得更加高效和可维护。LINQ 查询:使用 LINQ 来查询数据,简化了 SQL 语句的书写。延迟加载(Lazy Loading):按需加载相关数据,避免不必要的数据查询。显式加载(Explicit Loading)

这里只有干货:从 Modbus 通信到 MES 对接,从 YOLO 训练到工控机部署,带你搞定工业软件开发全流程。 1262

如何管理Entity Framework中得事务

http://msdn.microsoft.com/en-us/library/bb738523.aspxThis topic provides an example of how to define a transaction that coordinates making changes to objects in an object context with other ext...

weixin_30802273的博客 78
上一篇: SQL Server 2016 中有外键的表无法被Truncate,只能被Delete
下一篇: EF Core中Key属性相同的实体只能被跟踪(track)一次
davy57345
博客等级 码龄12年 8粉丝 123原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符  | 博主筛选后可见
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值