184  
查询码:00000148
EF上下文怎么优化怎么保证线程内唯一
作者: 史伟 于 2020年05月14日 发布在分类 / FM组 / FM服务 下,并于 2020年05月14日 编辑
EF 数据库 DDD 仓储

          本人在EF3.5版本刚发布的时候那时候就使用在项目中,好多年前了,那时候就考虑到EF上下文怎么创建的问题,以下是浅谈

          在一次请求中,即当前的一个请求线程中,刚开始的时候在使用EF的时候每次都new一个,当然为了自动释放对象我们会用using包起来(数据库连接是CLR非托管资源,系统不会自动释放), 但是如果有一个业务逻辑调用了多个dal层的方法,交互数据库多次,这样效率会低一些,而且在使用EF的情况下,我们通常把SaveChange这个方法提到业务逻辑层,不保证同一个业务逻辑使用的是同一个上下文对象,事务,工作单元模式(DDD,仓储以后会发相关文章)将无法实现。而且可能造成数据混乱,每次创建的对象执行相应的数据库操作,与此同时,同一次的请求可能包含对数据的不同操作。其他的EF对象内获得的数据可能已经是“过期”的了。即数据可能变动过。

        关键就是上下文对象的创建问题。这里最先当然想到Singleton,不过在这里,不适合用,原因是使用单例模式,会使EF对象得不到及时的资源释放。想象一下,无数个请求对数据库的访问,DbContext对象容器无数次增加对Model对象的变更监控,内存就爆了。而且因为EF对象不是简单的对象包含数据库实体以及Iqueryable等等。

       最先开始使用的数据巢也就是CallContext保证在线程内唯一,每一个请求使用同一个上下文 CallContext具体说明请翻阅MSDN  接下来废话不多说 上代码

/// <summary>
    ///SW 用来创建EF上下文对象,且保证线程内唯一。
    /// </summary>
    public class DbContextFactory
    {
        //DbContext在System.Data.Entity;中,不过这里直接只引用这一个不行,还有EF其他的一些NameSpace所以直接添加一个实体模型,所有引用都进来了,然后再把模型删了
        public static DbContext GetDbContext()
        {
            DbContext dbContext = (DbContext)CallContext.GetData("dbContext");
            if (dbContext == null)
            {
                dbContext = new SwEntities();
                CallContext.SetData("dbContext", dbContext);
            }
            return dbContext;
        }
    }
 如果想保证一些并发 请使用行锁Lock 这里不是重点不细说

    这样用了一段时间,思考了一下发现有一些问题,上面使用CallContext来存储有什么问题?就是说上面是把上下文对象依赖于一个线程。那么由于线程池的存在,线程在处理完一个请求之后,并没有被销毁,存储在CallContext中的上下文对象也一直存在,如果是下一次拿出这个线程去处理另一个请求,这个上下文对象其实也在不断的膨胀,只不过比全局的膨胀的稍微慢一些。而且,有时候一个线程并不一定是拿去处理请求了,如果是服务器拿去处理其他的业务,那就可能引发一些其他的问题,不能解决本质问题。

    通过查阅资料研究发现 其实我们还有更好的办法,在HttpContext中有一个Items属性,它也可以用来保存key-value,这就完美了,一次请求正好对应着一个HttpContext,请求结束,它自动释放,EF上下文也就不存在了。把上面代码中的CallContext改为HttpContext.Current.Items,废话不多说,上代码:


public static DbContext DbContext()
        {
            DbContext dbContext = HttpContext.Current.Items["dbContext"] as DbContext;
            if (dbContext == null)
            {
                dbContext = new SwEntities();
                HttpContext.Current.Items["dbContext"] =  dbContext;
            }
            return dbContext;
        }





 推荐知识

 历史版本

修改日期 修改人 备注
2020-05-14 20:42:51[当前版本] 史伟 创建版本

知识分享平台 -V 4.8.7 -wcp