zoukankan      html  css  js  c++  java
  • Entity Framework with NOLOCK

           在SqlServer中,频繁在同一个数据库表同时进行读写的时候,会存在锁的问题,也就是在前一个insert、update、delete事务操作完毕之前,你不能进行读取,必须要等到操作完毕,你才能进行select操作,目的是为了防止并发操作而读到脏数据,在SQL语句中,如果能容忍这种情况、加快查询速度,可以忽略锁进行查询:

    select * from [User] with(nolock) 

    但是如果你项目中使用EntityFramework,可以使用下面这段代码进行nolock查询:需要添加System.Transactions程序集的引用


    //declare the transaction options
    var transactionOptions = new System.Transactions.TransactionOptions();
    //set it to read uncommited
    transactionOptions.IsolationLevel = System.Transactions.IsolationLevel.ReadUncommitted;
    //create the transaction scope, passing our options in
    using (var transactionScope = new System.Transactions.TransactionScope(System.Transactions.TransactionScopeOption.Required, transactionOptions))
    {
        //declare our context
        using (var context = new MyEntityConnection())
        {
            //any reads we do here will also read uncomitted data
            //...
            //...
        }
        //don't forget to complete the transaction scope
        transactionScope.Complete();
    }

    改进,如果项目里有多处地方都需要nolock查询,这段代码就需要不断的拷贝了,这时候需要考虑进行封装,很明显,外层代码可以很容易的抽出来,但是,里面的代码段是不确定的,如果封装的话,执行的时候,就需要传一个代码片段进去,委托在这种情况就派上用场了,我们可以使用委托来改进一下,也就是查询数据库时候的逻辑代码代由委托传递进去。

            public static void NoLockInvokeDB(Action action)
            {
                var transactionOptions = new System.Transactions.TransactionOptions();
                transactionOptions.IsolationLevel = System.Transactions.IsolationLevel.ReadUncommitted;
                using (var transactionScope = new System.Transactions.TransactionScope(System.Transactions.TransactionScopeOption.Required, transactionOptions))
                {
                    try
                    {
                        action();
                    }
                    finally
                    {
                        transactionScope.Complete();
                    }
                }
            }
    使用的时候也很简单:
    NoLockInvokeDB(() =>
    { using (var db = new TicketDB()) { lst = db.User.ToList(); } });

    如果你不太习惯Action这种微软高度封装的委托的写法(其本质就是委托),可以继续看下去原始委托的写法:(我个人一直的观点是,微软喜欢搞高度封装的东西,想让程序员提高编程工作效率,但是,初入门的程序员因为不知道其中的原理,只会使用,所以就成了真真正正的代码农民工,所以,我们在工作学习的过程中,不要因为使用而使用,多去探讨其本质实现,对自己的提高有帮助。)

      public class Helper
        {
            public void NoLockInvokeDB(EFdelegate d)
            {
                var transactionOptions = new System.Transactions.TransactionOptions();
                transactionOptions.IsolationLevel = System.Transactions.IsolationLevel.ReadUncommitted;
                using (var transactionScope = new System.Transactions.TransactionScope(System.Transactions.TransactionScopeOption.Required, transactionOptions))
                {
                    d();
                    transactionScope.Complete();
                }
            }
        }
        public delegate void EFdelegate();

    调用也非常简单

     EFdelegate d = new EFdelegate(() => {
                    //这里写传递的代码段
                });

    如果不习惯这种匿名函数的写法的话,那就写全了。

    protected void Page_Load(object sender, EventArgs e)
    {
        EFdelegate d = new EFdelegate(SonFun);
    }
    
    public void SonFun()
    {
     //这里写传递的代码片段
    }
    参考文献:

    http://stackoverflow.com/questions/926656/entity-framework-with-nolock



    2018-12-28 Update
    现在项目已经废除了上述的NoLockInvokeDB的写法了,改成下面这种使用方法。在DBContext类里定义NoLock、WithLock方法,实际上就是在执行你的业务SQL之前,先执行NoLock、WithLock操作
            /// <summary>
            ///  base.Database.ExecuteSqlCommand("SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;");
            ///  设置后依然可以SaveChanges(),推荐需要SaveChanges()时先调用下WithLock()
            /// </summary>
            public void NoLock()
            {
                base.Database.ExecuteSqlCommand("SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;");
            }
    
            /// <summary>
            ///  base.Database.ExecuteSqlCommand("SET TRANSACTION ISOLATION LEVEL READ COMMITTED;");
            ///  这个是数据库默认设置。
            /// </summary>
            public void WithLock()
            {
                base.Database.ExecuteSqlCommand("SET TRANSACTION ISOLATION LEVEL READ COMMITTED;");
            }

    使用的时候,也非常简单。在查询之前,先使用db.NoLock() 即可。

                using (var db = new ProductDB())
                {
                    db.NoLock();
                    var data= db.Person.ToList();
                }



  • 相关阅读:
    什么是封装?
    table
    POM文件
    Maven环境的搭建
    什么是maven
    J2EE的三层经典结构
    DOM对象和jQuery对象对比
    jQuery常用选择器分类
    什么是JQuery?它的特点是什么?
    jQuery准备函数语法
  • 原文地址:https://www.cnblogs.com/waynechan/p/3178317.html
Copyright © 2011-2022 走看看