全國最多中醫師線上諮詢網站-台灣中醫網
發文 回覆 瀏覽次數:3238
推到 Plurk!
推到 Facebook!

MS SQL + ADO 如何知道該筆 RECORD 是否別人正在 Edit

缺席
cjtsif
一般會員


發表:12
回覆:13
積分:5
註冊:2002-09-18

發送簡訊給我
#1 引用回覆 回覆 發表時間:2018-08-11 15:06:19 IP:27.242.xxx.xxx 未訂閱
MS SQL + ADO 
ADODataSet1.CursorType=clUseClient
ADODataSet1.LockType=ltOptimistic

在多人作業的環境,
ADODataSet1.Edit 後,
在Post之前,若該筆record有別的使用者修改並post過,
ADODataSet1.Post會有Error:[找不到要更新的資料列。最後讀取的值已被變更。]

我想在ADODataSet1.BeforeEdit,查看資料庫該筆 RECORD 是否有別人正在 Edit
若有,則 abort

本以為大家都會遇到同樣問題,應該是有很多解答
但爬文許久,找不到答案

請大家幫忙,謝謝
sryang
尊榮會員


發表:39
回覆:762
積分:920
註冊:2002-06-27

發送簡訊給我
#2 引用回覆 回覆 發表時間:2018-08-15 08:26:31 IP:59.127.xxx.xxx 未訂閱
請 Google「樂觀並行」

===================引 用 cjtsif 文 章===================
MS SQL ADO
ADODataSet1.CursorType=clUseClient
ADODataSet1.LockType=ltOptimistic

在多人作業的環境,
ADODataSet1.Edit 後,
在Post之前,若該筆record有別的使用者修改並post過,
ADODataSet1.Post會有Error:[找不到要更新的資料列。最後讀取的值已被變更。]

我想在ADODataSet1.BeforeEdit,查看資料庫該筆 RECORD 是否有別人正在 Edit
若有,則 abort

本以為大家都會遇到同樣問題,應該是有很多解答
但爬文許久,找不到答案

請大家幫忙,謝謝
------
歡迎參訪 "腦殘賤貓的備忘錄" http://maolaoda.blogspot.com/
cjtsif
一般會員


發表:12
回覆:13
積分:5
註冊:2002-09-18

發送簡訊給我
#3 引用回覆 回覆 發表時間:2018-08-15 10:56:13 IP:39.9.xxx.xxx 未訂閱
我的做法的確是「樂觀並行」:Start Modify -> Validate -> Commit/Rollback

我想做到
1.Start Modify之前先查看該筆 RECORD 是否有別人已進入Modify

2.干脆不要 Validate,通通以user所看到維護的Commit就好

上面任何一種方式都好,
不知在delphi ado MSSQL,要如何做?
sryang
尊榮會員


發表:39
回覆:762
積分:920
註冊:2002-06-27

發送簡訊給我
#4 引用回覆 回覆 發表時間:2018-08-15 13:38:38 IP:59.127.xxx.xxx 未訂閱
「Start Modify之前先查看該筆 RECORD 是否有別人已進入Modify」
==> 除非你用另一個 table 記錄,否則做不到

「干脆不要 Validate,通通以user所看到維護的Commit就好」
==> 這跟沒有並行控制一樣,有資料被互相蓋掉的危險

樂觀並行 Validate 的方法,不是在 Edit 之前,而是 Post 之前
(在 Edit 之前檢核就是悲觀並行)
會在每個資料表加入時間戳記的欄位或是記錄版本號欄位,我推薦記錄版本號欄位。
記錄版本號 INSERT 時寫 1,每次 UPDATE 都加 1
Post 之前去 select 一次,看看 table 裡的記錄版本號是否與手上的一樣,若不一樣則提醒 user,重新查詢編輯

至於為什麼不是在 Edit 之前,因為你不能預期進入 Edit 之後,電話來了講個 10 分鐘的狀況

===================引 用 cjtsif 文 章===================
我的做法的確是「樂觀並行」:Start Modify -> Validate -> Commit/Rollback

我想做到
1.Start Modify之前先查看該筆 RECORD 是否有別人已進入Modify

2.干脆不要 Validate,通通以user所看到維護的Commit就好

上面任何一種方式都好,
不知在delphi ado MSSQL,要如何做?
------
歡迎參訪 "腦殘賤貓的備忘錄" http://maolaoda.blogspot.com/
編輯記錄
sryang 重新編輯於 2018-08-15 13:43:44, 註解 無‧
sryang 重新編輯於 2018-08-15 13:44:17, 註解 無‧
cjtsif
一般會員


發表:12
回覆:13
積分:5
註冊:2002-09-18

發送簡訊給我
#5 引用回覆 回覆 發表時間:2018-08-15 17:42:32 IP:211.72.xxx.xxx 未訂閱
感恩sryang兄回覆,

事實上,我目前的程式,應該就是跟sryang兄提的方式一樣
在 Post 之前 ,若有ADODataSet1.onPostError,
程式檢查NativeError,若為此項error,就通知user,重新select查詢編輯

但user反應,他改了20多個欄位,不想再重打
希望他Edit之後Post之前,別人不能再Edit

另外,
sryang兄提到:
1.「Start Modify之前先查看該筆 RECORD 是否有別人已進入Modify」
==> 除非你用另一個 table 記錄,否則做不到

我有試著在Table加兩個欄位 isEditing(是否正在Edit) StartEditTM(Edit開始時間)
Edit時:
Step 1.if isEditing then abort
Step 2.Update Table Set isEditing=True,StartEditTM=Now, Post
Step 3.進入Edit,user編修
Step 4.Post前 Set isEditing=False,StartEditTM=''

雖然可行,但這樣有點麻煩,希望有比較簡單的方法

2.「干脆不要 Validate,通通以user所看到維護的Commit就好」
==> 這跟沒有並行控制一樣,有資料被互相蓋掉的危險
Delphi ADO 要如何"不要"並行控制(資料被互相蓋掉沒關係)
編輯記錄
cjtsif 重新編輯於 2018-08-15 19:44:33, 註解 無‧
cjtsif 重新編輯於 2018-08-15 19:46:01, 註解 無‧
cjtsif 重新編輯於 2018-08-15 19:52:55, 註解 無‧
Jasonwong
版主


發表:49
回覆:931
積分:581
註冊:2006-10-27

發送簡訊給我
#6 引用回覆 回覆 發表時間:2018-08-15 21:13:41 IP:125.227.xxx.xxx 未訂閱
會有 "找不到要更新的資料列。最後讀取的值已被變更" 的錯誤訊息,主要原因是因為你的 ADO 的是 WHERE ALL,也就是你要 POST 資料時, SQL SERVER 會先去 WHERE 要 POST 的資料列,而 WHERE ALL 會讓 SQL SERVER 的 SELECT 語法變成
"SELECT * FROM TABLE WHERE (全部欄位)",所以你只要有一個欄位被改變你就會得到以上的錯誤訊息。

要解決此問題就要把 WHERE ALL 改成 WHERE KEY

每個欄位屬性表裡都有一個 ProviderFlags 屬性,將 pfInUpdate 打勾,其他不要勾。只有 KEY 欄位除了將 pfInUpdate 打勾外,還要將 pfInWhere 及 pfInKey 這兩個屬性打勾。


這樣即可
------
聰明的人,喜歡猜心;雖然每次都猜對了,卻失去了自己的心
傻氣的人,喜歡給心;雖然每次都被笑了,卻得到了別人的心
sryang
尊榮會員


發表:39
回覆:762
積分:920
註冊:2002-06-27

發送簡訊給我
#7 引用回覆 回覆 發表時間:2018-08-16 02:17:03 IP:59.127.xxx.xxx 未訂閱
預設的 where all 也是一種樂觀並行機制,最簡單的一種
------
歡迎參訪 "腦殘賤貓的備忘錄" http://maolaoda.blogspot.com/
cjtsif
一般會員


發表:12
回覆:13
積分:5
註冊:2002-09-18

發送簡訊給我
#8 引用回覆 回覆 發表時間:2018-08-16 12:55:13 IP:211.72.xxx.xxx 未訂閱
殘念です,WHERE ALL / WHERE KEY 和我的問題好像沒有關係

無論任何一個
ADODataSet1.Edit 後,
在Post之前,若該筆record有別的使用者修改並post過,
ADODataSet1.Post會有Error:[找不到要更新的資料列。最後讀取的值已被變更。]
找不到要更新的資料列。最後讀取的值已被變更" 的錯誤訊息,主要原因是因為你的 ADO 的是 WHERE ALL
編輯記錄
cjtsif 重新編輯於 2018-08-20 20:50:32, 註解 無‧
kurumba
一般會員


發表:0
回覆:1
積分:0
註冊:2018-09-13

發送簡訊給我
#9 引用回覆 回覆 發表時間:2018-09-13 09:40:17 IP:59.120.xxx.xxx 未訂閱
procedure TProcessForm.ADODataSet1AfterOpen(DataSet: TDataSet);
begin
ADODataSet1.Properties.Get_Item('Update Criteria').Value := 0;
end;

===================引 用 cjtsif 文 章===================
MS SQL ADO
ADODataSet1.CursorType=clUseClient
ADODataSet1.LockType=ltOptimistic

在多人作業的環境,
ADODataSet1.Edit 後,
在Post之前,若該筆record有別的使用者修改並post過,
ADODataSet1.Post會有Error:[找不到要更新的資料列。最後讀取的值已被變更。]
...............
it1506
初階會員


發表:32
回覆:89
積分:49
註冊:2011-02-16

發送簡訊給我
#10 引用回覆 回覆 發表時間:2018-09-28 10:26:07 IP:59.120.xxx.xxx 未訂閱
在 SQL Server 中,支援了 11 種不同物件的鎖定機制,資料庫引擎會自己判斷資源的存取狀況決定要使用何種鎖定機制。 而資料庫引擎在決定使用何種鎖定策略前,會先決定鎖定的控制類型,先由用戶端程式所要求的控制類型來處理,若用戶端程式沒有要求時才會由資料庫的預設值來處理,而鎖定的控制類型有兩種:
  • 悲觀鎖定 (Pessimistic Locking),表示資料庫引擎認為更新資料的動作不會順利,因此會將資料的鎖定時間拉長到鎖定被釋放為止,這會保證更新一定會寫入,但缺點就是會拉長鎖定時間。
  • 樂觀鎖定 (Optimistic Locking),表示資料庫引擎認為更新資料的動作一定會順利,因此不會對讀取的動作進行鎖定,讓讀取的速度可以加快,但如果在讀取時有別的使用者修改了資料以致於讀取不同步時,就會出現 Optimistic Locking Exception,也就是 DbConcurrencyException 例外狀況。
ADO 中支援了五種鎖定控制類型,分別是:
  • adLockBatchOptimistic (=4),指示在批次處理時使用樂觀鎖定。 在delphi裡是 TADOLockType.ltBatchOptimistic; 以此類推.
  • adLockOptimistic (=3),指示以樂觀鎖定方式處理。
  • adLockPessimistic (=2),指示以悲觀鎖定方式處理。
  • adLockReadOnly (=1),指示將資料集設為唯讀。
  • adLockUnspecified (=-1),不明確設定鎖定類型。
編輯記錄
it1506 重新編輯於 2018-09-28 10:28:20, 註解 無‧
wsx1688
一般會員


發表:0
回覆:0
積分:0
註冊:2024-04-08

發送簡訊給我
#11 引用回覆 回覆 發表時間:2024-04-08 16:58:57 IP:38.54.xxx.xxx 未訂閱
瀨5280366和TG搜索nini9595 火辣正妹讓你享受AV裏的性愛高潮 你有膽來嘗試嗎~!
系統時間:2024-04-28 8:05:07
聯絡我們 | Delphi K.Top討論版
本站聲明
1. 本論壇為無營利行為之開放平台,所有文章都是由網友自行張貼,如牽涉到法律糾紛一切與本站無關。
2. 假如網友發表之內容涉及侵權,而損及您的利益,請立即通知版主刪除。
3. 請勿批評中華民國元首及政府或批評各政黨,是藍是綠本站無權干涉,但這裡不是政治性論壇!