EntiryFramework中事务操作(三)事务回滚数据模型和数据库不对应问题

本文主要是介绍EntiryFramework中事务操作(三)事务回滚数据模型和数据库不对应问题,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

一、关于事务回滚数据模型和数据库不对应问题

1.在使用事务时,无论是使用DbContextTransaction,还是使用TransactionScope,如果在事务中出现异常而回滚,都有可能出现这种情况,数据库数据已经回滚,但是实体模型缓存没有回滚。出现数据的不一致行。

2.这种情况出现的原因:

   1.EF中对于查询的实体对象在内存中有缓存,用于数据的状态跟踪,提升性能。

   2.在程序中使用相同的数据上下文。

二、解决方案

解决方案1.在程序中不使用同一个数据库上下文

也就是说事务回滚后,放弃当前使用上下文。

这种方式需要注意,对于事务最好使用TransactionScope,因为在同一DbContextTransaction事务中有两个上线文实例会出现死锁。

代码实例:

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);}
}
//此位置获取的数据和数据库对应
Test1 _context3 = new Test1();
Console.WriteLine(_context3.Areas.FirstOrDefault(q => q.AreaLevel == 1).AreaName);


对于目前版本6.0,在事务执行失败后,放弃当前上下文,是EF官方给的一个方案,不知道将来是否会有更好的解决方案。

具体查看:https://msdn.microsoft.com/en-us/library/dn456833(v=vs.113).aspx


解决方案2:如果在事务异常后还要使用当前上下文,并且程序中数据量不是很大或者不需要太考虑性能的情况下,可以手动遍历所有的对象,设置为未跟踪来处理。

//手动修改所有缓存模型对象的状态为未跟踪
foreach (var item in _context.ChangeTracker.Entries())
{item.State = System.Data.Entity.EntityState.Deleted;
}
实例代码:

Test1 _context = new Test1();
try
{using (TransactionScope tran = new TransactionScope()){Area province = _context.Areas.FirstOrDefault(q => q.AreaLevel == 1);province.AreaName = province.AreaName + "1";_context.SaveChanges();Console.WriteLine(_context.Areas.FirstOrDefault(q => q.AreaLevel == 1).AreaName);throw new Exception("测试");tran.Complete();}
}
catch (Exception)
{
}
//手动修改所有缓存模型对象的状态为未跟踪
foreach (var item in _context.ChangeTracker.Entries())
{item.State = System.Data.Entity.EntityState.Deleted;
}
Console.WriteLine(_context.Areas.AsNoTracking().FirstOrDefault(q => q.AreaLevel == 1).AreaName);

三、对于只有一个数据库上下文的解决方案实例

1.定义处理提交和回滚类,在回滚时手动清空跟踪状态

public class EFTransaction : IDisposable
{/// <summary>/// 当前事务对象/// </summary>private DbContextTransaction tran = null;public EFTransaction(DbContextTransaction tran){this.tran = tran;}/// <summary>/// 提交/// </summary>public void Commit(){tran.Commit();}/// <summary>/// 混滚操作/// </summary>public void Rollback(){Console.WriteLine("执行回滚操作");tran.Rollback();//执行其他处理foreach (var item in Program._Context.ChangeTracker.Entries()){item.State = System.Data.Entity.EntityState.Detached;}}public void Dispose(){Console.WriteLine("正在释放资源");tran.Dispose();}
}
2.在使用事务时,操作自定义类的对象

public static MenuModel _Context = new MenuModel();
static void TestSix()
{//使用事务扩展using (var tran = new EFTransaction(_Context.Database.BeginTransaction())){try{Menu.Menu first = _Context.Menus.First();Console.WriteLine(first.MenuName);first.MenuName = "abc";first.Model.ModelName = "123";_Context.SaveChanges();throw new Exception("测试异常");tran.Commit();}catch (Exception ex){tran.Rollback();}}Console.WriteLine(_Context.Menus.First().MenuName);//如果不清除跟踪状态,返回abc,和数据库不一致
}


四、在目前EF6.0的版本中,对于事务异常官方说明:

事务提交期间的实体框架连接故障
更新日期:2016年10月23日
一般来说,当连接失败时,回滚当前事务.。但是,如果在事务提交时连接被删除,则事务的结果状态未知.。看到这个博客张贴更多的细节。
目前EF不提供任何特殊的工具来处理这种情况。的sqlazureexecutionstrategy不会重试操作如果这样失败。
有几种方法来处理这个问题:
选项1 -什么都不做
在事务提交过程中连接失败的可能性很低,所以如果实际发生这种情况,您的应用程序可能会失败,这可能是可以接受的.。
选项2 -使用数据库重置状态
放弃当前的DbContext
创建一个新的DbContext和从数据库恢复应用程序的状态。
通知用户最近的操作可能没有成功地完成
选项3 -手动跟踪事务
将一个非跟踪表添加到用于跟踪事务状态的数据库中.。
在每个事务开始时将一行插入到表中.。
如果在提交过程中连接失败,请检查数据库中相应行的存在.。
如果该行存在,则继续正常运行,因为事务已成功提交.
如果行不存在,请使用执行策略重试当前操作.。
如果提交成功,请删除相应的行以避免表的增长.。

更多:

EntiryFramework中事务操作(二)

EntiryFramework中事务操作实例


这篇关于EntiryFramework中事务操作(三)事务回滚数据模型和数据库不对应问题的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1016987

相关文章

使用Python的requests库来发送HTTP请求的操作指南

《使用Python的requests库来发送HTTP请求的操作指南》使用Python的requests库发送HTTP请求是非常简单和直观的,requests库提供了丰富的API,可以发送各种类型的HT... 目录前言1. 安装 requests 库2. 发送 GET 请求3. 发送 POST 请求4. 发送

MySQL 表空却 ibd 文件过大的问题及解决方法

《MySQL表空却ibd文件过大的问题及解决方法》本文给大家介绍MySQL表空却ibd文件过大的问题及解决方法,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考... 目录一、问题背景:表空却 “吃满” 磁盘的怪事二、问题复现:一步步编程还原异常场景1. 准备测试源表与数据

解决Nginx启动报错Job for nginx.service failed because the control process exited with error code问题

《解决Nginx启动报错Jobfornginx.servicefailedbecausethecontrolprocessexitedwitherrorcode问题》Nginx启... 目录一、报错如下二、解决原因三、解决方式总结一、报错如下Job for nginx.service failed bec

SysMain服务可以关吗? 解决SysMain服务导致的高CPU使用率问题

《SysMain服务可以关吗?解决SysMain服务导致的高CPU使用率问题》SysMain服务是超级预读取,该服务会记录您打开应用程序的模式,并预先将它们加载到内存中以节省时间,但它可能占用大量... 在使用电脑的过程中,CPU使用率居高不下是许多用户都遇到过的问题,其中名为SysMain的服务往往是罪魁

Go语言连接MySQL数据库执行基本的增删改查

《Go语言连接MySQL数据库执行基本的增删改查》在后端开发中,MySQL是最常用的关系型数据库之一,本文主要为大家详细介绍了如何使用Go连接MySQL数据库并执行基本的增删改查吧... 目录Go语言连接mysql数据库准备工作安装 MySQL 驱动代码实现运行结果注意事项Go语言执行基本的增删改查准备工作

MySQ中出现幻读问题的解决过程

《MySQ中出现幻读问题的解决过程》文章解析MySQLInnoDB通过MVCC与间隙锁机制在可重复读隔离级别下解决幻读,确保事务一致性,同时指出性能影响及乐观锁等替代方案,帮助开发者优化数据库应用... 目录一、幻读的准确定义与核心特征幻读 vs 不可重复读二、mysql隔离级别深度解析各隔离级别的实现差异

C++ vector越界问题的完整解决方案

《C++vector越界问题的完整解决方案》在C++开发中,std::vector作为最常用的动态数组容器,其便捷性与性能优势使其成为处理可变长度数据的首选,然而,数组越界访问始终是威胁程序稳定性的... 目录引言一、vector越界的底层原理与危害1.1 越界访问的本质原因1.2 越界访问的实际危害二、基

Python多线程应用中的卡死问题优化方案指南

《Python多线程应用中的卡死问题优化方案指南》在利用Python语言开发某查询软件时,遇到了点击搜索按钮后软件卡死的问题,本文将简单分析一下出现的原因以及对应的优化方案,希望对大家有所帮助... 目录问题描述优化方案1. 网络请求优化2. 多线程架构优化3. 全局异常处理4. 配置管理优化优化效果1.

Python使用python-pptx自动化操作和生成PPT

《Python使用python-pptx自动化操作和生成PPT》这篇文章主要为大家详细介绍了如何使用python-pptx库实现PPT自动化,并提供实用的代码示例和应用场景,感兴趣的小伙伴可以跟随小编... 目录使用python-pptx操作PPT文档安装python-pptx基础概念创建新的PPT文档查看

MySQL 数据库表操作完全指南:创建、读取、更新与删除实战

《MySQL数据库表操作完全指南:创建、读取、更新与删除实战》本文系统讲解MySQL表的增删查改(CURD)操作,涵盖创建、更新、查询、删除及插入查询结果,也是贯穿各类项目开发全流程的基础数据交互原... 目录mysql系列前言一、Create(创建)并插入数据1.1 单行数据 + 全列插入1.2 多行数据