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();
                }



  • 相关阅读:
    Codeforces Round #592 (Div. 2)C. The Football Season(暴力,循环节)
    Educational Codeforces Round 72 (Rated for Div. 2)D. Coloring Edges(想法)
    扩展KMP
    poj 1699 Best Sequence(dfs)
    KMP(思路分析)
    poj 1950 Dessert(dfs)
    poj 3278 Catch That Cow(BFS)
    素数环(回溯)
    sort与qsort
    poj 1952 buy low buy lower(DP)
  • 原文地址:https://www.cnblogs.com/waynechan/p/3178317.html
Copyright © 2011-2022 走看看