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

相关文章

MySQL数据库双机热备的配置方法详解

《MySQL数据库双机热备的配置方法详解》在企业级应用中,数据库的高可用性和数据的安全性是至关重要的,MySQL作为最流行的开源关系型数据库管理系统之一,提供了多种方式来实现高可用性,其中双机热备(M... 目录1. 环境准备1.1 安装mysql1.2 配置MySQL1.2.1 主服务器配置1.2.2 从

SpringBoot基于注解实现数据库字段回填的完整方案

《SpringBoot基于注解实现数据库字段回填的完整方案》这篇文章主要为大家详细介绍了SpringBoot如何基于注解实现数据库字段回填的相关方法,文中的示例代码讲解详细,感兴趣的小伙伴可以了解... 目录数据库表pom.XMLRelationFieldRelationFieldMapping基础的一些代

IDEA和GIT关于文件中LF和CRLF问题及解决

《IDEA和GIT关于文件中LF和CRLF问题及解决》文章总结:因IDEA默认使用CRLF换行符导致Shell脚本在Linux运行报错,需在编辑器和Git中统一为LF,通过调整Git的core.aut... 目录问题描述问题思考解决过程总结问题描述项目软件安装shell脚本上git仓库管理,但拉取后,上l

idea npm install很慢问题及解决(nodejs)

《ideanpminstall很慢问题及解决(nodejs)》npm安装速度慢可通过配置国内镜像源(如淘宝)、清理缓存及切换工具解决,建议设置全局镜像(npmconfigsetregistryht... 目录idea npm install很慢(nodejs)配置国内镜像源清理缓存总结idea npm in

pycharm跑python项目易出错的问题总结

《pycharm跑python项目易出错的问题总结》:本文主要介绍pycharm跑python项目易出错问题的相关资料,当你在PyCharm中运行Python程序时遇到报错,可以按照以下步骤进行排... 1. 一定不要在pycharm终端里面创建环境安装别人的项目子模块等,有可能出现的问题就是你不报错都安装

idea突然报错Malformed \uxxxx encoding问题及解决

《idea突然报错Malformeduxxxxencoding问题及解决》Maven项目在切换Git分支时报错,提示project元素为描述符根元素,解决方法:删除Maven仓库中的resolv... 目www.chinasem.cn录问题解决方式总结问题idea 上的 maven China编程项目突然报错,是

使用Java填充Word模板的操作指南

《使用Java填充Word模板的操作指南》本文介绍了Java填充Word模板的实现方法,包括文本、列表和复选框的填充,首先通过Word域功能设置模板变量,然后使用poi-tl、aspose-words... 目录前言一、设置word模板普通字段列表字段复选框二、代码1. 引入POM2. 模板放入项目3.代码

Python爬虫HTTPS使用requests,httpx,aiohttp实战中的证书异步等问题

《Python爬虫HTTPS使用requests,httpx,aiohttp实战中的证书异步等问题》在爬虫工程里,“HTTPS”是绕不开的话题,HTTPS为传输加密提供保护,同时也给爬虫带来证书校验、... 目录一、核心问题与优先级检查(先问三件事)二、基础示例:requests 与证书处理三、高并发选型:

利用Python操作Word文档页码的实际应用

《利用Python操作Word文档页码的实际应用》在撰写长篇文档时,经常需要将文档分成多个节,每个节都需要单独的页码,下面:本文主要介绍利用Python操作Word文档页码的相关资料,文中通过代码... 目录需求:文档详情:要求:该程序的功能是:总结需求:一次性处理24个文档的页码。文档详情:1、每个

Python内存管理机制之垃圾回收与引用计数操作全过程

《Python内存管理机制之垃圾回收与引用计数操作全过程》SQLAlchemy是Python中最流行的ORM(对象关系映射)框架之一,它提供了高效且灵活的数据库操作方式,本文将介绍如何使用SQLAlc... 目录安装核心概念连接数据库定义数据模型创建数据库表基本CRUD操作创建数据读取数据更新数据删除数据查