1. 程式人生 > >在OQL上使用UPDLOCK鎖定查詢結果,安全的更新實體資料

在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資料庫。