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

 





免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM