首页 技术 正文
技术 2022年11月21日
0 收藏 869 点赞 3,743 浏览 2318 个字

博客地址 http://blog.csdn.net/foxdave

本文主要记录近两天针对项目发生的数据访问问题的分析研究过程与系统架构优化,我喜欢说通俗的白话,高手轻拍

1. 发现问题

系统新模块上线后,使用频率较高,故在实际使用和后期的问题重现测试中,产生了一下系列的数据访问错误

Entity Framework 数据并发访问错误原因分析与系统架构优化

Entity Framework 数据并发访问错误原因分析与系统架构优化

Entity Framework 数据并发访问错误原因分析与系统架构优化

Entity Framework 数据并发访问错误原因分析与系统架构优化

Entity Framework 数据并发访问错误原因分析与系统架构优化

错误是比较常见的错误

2. 分析问题

系统的架构为前端、业务层与数据层三层架构,采用Entity Framework 3.5作为数据处理技术,采用shared context per request模式,参照的是codeplex上的一个示例。示例地址(此文通俗易懂,代码结构也很清晰,个人很喜欢)

Entity模式的代码如下:

public partial class SPMIPEntities
{
public static SPMIPEntities Context
{
get
{
string objectContextKey = "MIP_" + HttpContext.Current.GetHashCode().ToString("x");
if (!HttpContext.Current.Items.Contains(objectContextKey))
{
HttpContext.Current.Items.Add(objectContextKey, new SPMIPEntities());
}
return HttpContext.Current.Items[objectContextKey] as SPMIPEntities;
}
}
}

基于以上,根据系统的报错位置研究Entity实例并发与共享的问题,搜索了一些entity framework相关的资料。此问题主要从两个角度去着手解决:缩短Entity实例的存在时间和降低Entity实例的共享性,并考虑性能,因为Entity需要手动Dispose。

首先添加手动Dispose逻辑,我们的项目为SharePoint应用程序,所以和一般的.net略有不同。自行开发了一个BasePage类,所有的应用程序页面都继承自该类,BasePage类又继承自LayoutsPageBase类,要做到使用完Entity后及时Dispose,最好也写在页面的类似结束请求的事件里,于是在后台敲上protected空格override空格D->发现可重写Dispose方法,大喜,代码如下:

public override void Dispose()
{
string objectContextKey = "MIP_" + HttpContext.Current.GetHashCode().ToString("x");
if (HttpContext.Current.Items.Contains(objectContextKey))
{
SPMIPEntities ctx = HttpContext.Current.Items[objectContextKey] as SPMIPEntities;
if (ctx != null)
{
ctx.Dispose();
HttpContext.Current.Items.Remove(objectContextKey);
}
}
base.Dispose();
}

修改之后部署,测试,发现报错了:

The ObjectContext instance has been disposed and can no longer be used for operations that require a connection

没理由会这样,因为每个请求都会实例化新的Entity,不可能会被提前释放。

调试代码,断点卡到第一段代码get下面。重启服务,访问系统,附加进程开始调试,第一次get进来了,new了一个Entity实例出去,页面加载了出来;刷新页面,发现没有再次中断,到这里,就非常的不合理了,肯定有忽视掉的地方,于是回过头来一层一层查看代码,发现业务层和数据层的类都被写成了单例模式,举例如下

public class DAC
{ #region 变量
// 本类对象
private static DAC _newNewInstance;
private SPMIPEntities ctx = null;
#endregion #region 构造函数 /// <summary>
/// 私有构造函数
/// </summary>
private DAC()
{
ctx = SPMIPEntities.Context;
} #endregion #region 公有方法 /// <summary>
/// 本类实例对象
/// </summary>
/// <returns>
/// 返回DAC对象
/// </returns>
public static DAC GetNewInstance()
{
if (_newNewInstance == null)
{
_newNewInstance = new DAC();
}
return _newNewInstance;
}
}

问题一定就在这里了,将单例模式改掉,修改为如下结构

public class DAC
{
private SPMIPEntities ctx = null; private DAC()
{
ctx = SPMIPEntities.Context;
} public static DAC GetNewInstance()
{
return new DAC();
}
}

修改完后部署重复上述步骤调试,预期中的结果。

下周再和团队一起系统地测试一遍,看看是不是有效果。

本来预期中的架构是没什么问题的,谁知当时又将操作类做成了单例模式而没有引起重视,为当前错误的爆发埋下了伏笔。架构还是应该多推敲,多考虑的。

要下班了,所以写的有些仓促;写得看起来很简单,但是研究的过程并不是特别简单,都是耗费时间的。特此记录。

相关推荐
python开发_常用的python模块及安装方法
adodb:我们领导推荐的数据库连接组件bsddb3:BerkeleyDB的连接组件Cheetah-1.0:我比较喜欢这个版本的cheeta…
日期:2022-11-24 点赞:878 阅读:9,031
Educational Codeforces Round 11 C. Hard Process 二分
C. Hard Process题目连接:http://www.codeforces.com/contest/660/problem/CDes…
日期:2022-11-24 点赞:807 阅读:5,520
下载Ubuntn 17.04 内核源代码
zengkefu@server1:/usr/src$ uname -aLinux server1 4.10.0-19-generic #21…
日期:2022-11-24 点赞:569 阅读:6,368
可用Active Desktop Calendar V7.86 注册码序列号
可用Active Desktop Calendar V7.86 注册码序列号Name: www.greendown.cn Code: &nb…
日期:2022-11-24 点赞:733 阅读:6,148
Android调用系统相机、自定义相机、处理大图片
Android调用系统相机和自定义相机实例本博文主要是介绍了android上使用相机进行拍照并显示的两种方式,并且由于涉及到要把拍到的照片显…
日期:2022-11-24 点赞:512 阅读:7,781
Struts的使用
一、Struts2的获取  Struts的官方网站为:http://struts.apache.org/  下载完Struts2的jar包,…
日期:2022-11-24 点赞:671 阅读:4,860