在OQL上使用UPDLOCK鎖定查詢結果,安全的更新實體數據

SqlServer查詢記錄的時候提供多種鎖定方式,其中UPDLOCK 的優勢是容許您讀取數據(不阻塞其它事務)並在之後更新數據,同時確保自從上次讀取數據後數據沒有被更改。當咱們用UPDLOCK來讀取記錄時能夠對取到的記錄加上更新鎖,從而加上鎖的記錄在其它的線程中是不能更改的只能等本線程的事務結束後才能更改。
有時候我須要控制某條記錄在我讀取後就不準再進行更新,那麼我就能夠將全部要處理當前記錄的查詢都加上更新鎖,以防止查詢後被其它事務修改.將事務的影響下降到最小。假如不這樣作,將整個表鎖定,這種作法將嚴重影響了性能。
看下面的查詢:
begin tran
select * from address WITH (UPDLOCK) where [Name]='Z'
waitfor delay '00:00:10' 
update address set [Name]='X' where [Name]='Z' 
commit tran

 

這個示例中,在讀取記錄後,等待10秒來模擬耗時的操做,以後再更新這條記錄。
上面這個例子可能比較抽象,讓咱們來舉一個實際的例子。
假設有一個投資產品表,當咱們查詢到該產品記錄後,要進行一系列的判斷,最後對該記錄進行更新。該記錄的狀態會影響到下一我的查詢到此記錄的處理。下面咱們來看看用SOD框架的OQL怎麼處理。
           decimal sumAmount = model.Amount + model.GvMoney;
            DateTime currentTime = DateTime.Now;
            AdoHelper db = AdoHelper.CreateHelper("defaultDB");
            
            db.BeginTransaction();
            try
            {
                //查詢相關產品餘額剩多少夠不夠買的
                var pro = EntityQuery<Pro_Products>.QueryObject(
                    OQL.From<Pro_Products>()
                        .With(OQL.SqlServerLock.UPDLOCK)
                        .Select()
                        .Where<Pro_Products>((cmp, p) => cmp.Property(p.proNumber) == model.ProNumber)
                        .END, db);
                if (pro == null)
                {
                    db.Rollback();
                    return new OrderingModel { Msg = "剩餘可投金額不足" };
                }
                //2015 08 06 打開原有註釋,限制投資金額  
                if (sumAmount < 10 || sumAmount % 10 != 0)
                {
                    db.Rollback();
                    return new OrderingModel { Msg = "投標金額不正確" };
                }

                //線下標下單時,不可以使用現金券 
                if (SetObject.IsOffline(pro.ProType))
                {
                    sumAmount = model.Amount;
                }
                if (pro.Surplus < sumAmount)
                {
                    db.Rollback();
                    return new OrderingModel { Msg = "剩餘可投金額不足" };
                }
                if (currentTime < pro.starttime)
                {
                    db.Rollback();
                    return new OrderingModel { Msg = "還未開始" };
                }
                var giveAward = 0;
                if (pro.Surplus == sumAmount)
                {
                    if (sumAmount >= 5000 && sumAmount < 10000)
                    {
                        giveAward = 1;
                    }
                    if (sumAmount >= 10000)
                    {
                        giveAward = 2;
                    }
                }
                //扣除產品可用金額
                pro.Surplus -= sumAmount;
                if (pro.Surplus == 0)//最後一筆 更新滿標狀態
                {
                    pro.Prostatus = "2";
                    //pro.Paymentime = currentTime.AddDays(1);
                    pro.Paymentime = currentTime;
                    //
                    pro.ProOrder = 0;
                }

                EntityQuery<Pro_Products>.Instance.Update(pro, db);
 
                //其它複雜的處理邏輯,更新其它表的操做,略...

                  db.Commit();

上面的操做,首先在AdoHelper對象上開啓事務,而後查詢投資產品實體的時候在With方法上加上 OQL.SqlServerLock.UPDLOCK 更新鎖,接着進行復制的業務處理,而後更新此實體記錄,以後還有複雜的其它業務操做,最後提交事務。數據庫

咱們看到,OQL的這種更新鎖操做,跟直接寫SQL語句操做很相似,OQL執行的時候也是這樣輸出SQL語句的,這樣確保數據記錄在併發的時候,安全的更新。安全

注意:OQL更新鎖目前只支持SqlServer數據庫。併發

相關文章
相關標籤/搜索