線上訂房服務-台灣趴趴狗聯合訂房中心
發文 回覆 瀏覽次數:2959
推到 Plurk!
推到 Facebook!

當多人共用同一記錄時。

答題得分者是:P.D.
t0288542
中階會員


發表:216
回覆:254
積分:94
註冊:2004-10-06

發送簡訊給我
#1 引用回覆 回覆 發表時間:2009-03-23 16:04:00 IP:60.248.xxx.xxx 訂閱
請問各位大大,

如果遇到多個使用者 同時在維護某一表格時,如何去防止 當A或B,同時對某一筆記錄作修改時,
A,動作比較快,B再修改後存檔就會有問題,
"更新的資料列 最後讀取的值己被變更"

各位大大,有什麼方法可以作。

thks
christie
資深會員


發表:28
回覆:299
積分:475
註冊:2005-03-25

發送簡訊給我
#2 引用回覆 回覆 發表時間:2009-03-23 17:15:13 IP:59.125.xxx.xxx 未訂閱
假設要UPDATE TABLE之前先要拿到KEYFLAG
SQL> SELECT * FROM TUPDFLAG;

KEYFLAG
-------------
980323

SQL>

舉例 Q1.SQL.Text:=DELETE FROM TUPDFLAG='980323';
Q1.ExecSQL;
也就是說Q1.ROWSAFFECTED >0 的人可以UPDATE TABLE。

===================引 用 t0288542 文 章===================
請問各位大大,

如果遇到多個使用者 同時在維護某一表格時,如何去防止 當A或B,同時對某一筆記錄作修改時,
A,動作比較快,B再修改後存檔就會有問題,
"更新的資料列 最後讀取的值己被變更"

各位大大,有什麼方法可以作。

thks
------
What do we live for if not to make life less difficult for each other?
P.D.
版主


發表:571
回覆:3880
積分:3666
註冊:2006-10-31

發送簡訊給我
#3 引用回覆 回覆 發表時間:2009-03-24 02:30:24 IP:61.67.xxx.xxx 未訂閱
1.不知道你對資料庫的認知有多深
2.不知道你使用的資料庫是那種
通常有以下幾種做法
1.一般稍具規模的資料庫引擎都具有"交易"模式, 進行異動前先啟動交易, 第二個進入者都無法針對該記錄進行異動
2.可以對異動資料庫在異動前, 先標記該筆記錄(以一個實體欄位做flag, 填入一個符號), 當每一個操作者企圖異動該記錄前, 都先檢查該flag的狀況, 當第一個異動者完成或放棄異動時, 由原異動者取消該標記
3.db檔具有自動偵測lock的功能, 所以可以很輕易知道記錄是否被異動
原則上, 所有異動模式, 建議最好在啟動edit 前先檢查記錄是否被人佔用, 而不要在回存時才去做這個動作
===================引 用 t0288542 文 章===================
請問各位大大,

如果遇到多個使用者 同時在維護某一表格時,如何去防止 當A或B,同時對某一筆記錄作修改時,
A,動作比較快,B再修改後存檔就會有問題,
"更新的資料列 最後讀取的值己被變更"

各位大大,有什麼方法可以作。

thks
t0288542
中階會員


發表:216
回覆:254
積分:94
註冊:2004-10-06

發送簡訊給我
#4 引用回覆 回覆 發表時間:2009-03-24 14:26:53 IP:60.248.xxx.xxx 訂閱
謝謝 christie 及 P.D. 兩位大大。

如以設 flag 欄位作判斷,我又想到一個問題,
當 A,B都同時停留在這一筆記錄查詢畫面,A動作快鎖定修改也作存檔,但B的畫面值沒有作同步,
那這種情況如何去解決呢,在修改時 畫面的值 和 資料庫的值 在一一比對,告訴B資料已被修改請重新作查詢動作。

請問各位大大,有什麼方法可解決。

麻煩大家。thks
christie
資深會員


發表:28
回覆:299
積分:475
註冊:2005-03-25

發送簡訊給我
#5 引用回覆 回覆 發表時間:2009-03-24 15:20:57 IP:59.125.xxx.xxx 未訂閱
這篇可參考

http://delphi.ktop.com.tw/board.php?cid=30&fid=66&tid=96041

資料庫與多人訂位問題?
------
What do we live for if not to make life less difficult for each other?
P.D.
版主


發表:571
回覆:3880
積分:3666
註冊:2006-10-31

發送簡訊給我
#6 引用回覆 回覆 發表時間:2009-03-24 16:22:45 IP:61.67.xxx.xxx 未訂閱
這的確是一個很大的難題, 因為 資料庫都有BUFFER的問題, 也就是一旦A,B,都載入記錄後, A異動並不會影響B, 因為如果會影響的話, 可能會造成世界大戰, 所以我能想到的一個辦法是利用 SOCKETSERVER, SOCKETCLIENT 來互相傳遞消息, 也就是當 A 異動儲存完成, 由 A 電腦發訊息(A當CLEINT)到 B 電腦(B當 SERVER), 當B收到訊息後, 重新 UPDATE 現在的資料庫, 但這當中又牽涉到太多的技術及KNOWHOW, 例如 如果 B正在編輯當中怎麼辦, 如果B 所SELECT 的範圍與 A 更新的記錄並無任何關係時, 如何做, 如果 B 沒有在資料庫中, 如果 不只 B電腦, 可能線上有10台, 20台在操作, 又怎麼辦? 當然還有更多的問題, 哦~~~我實在不敢想, 所以最簡單的方式是採被動執行, 不要去想主動這檔事吧!
===================引 用 t0288542 文 章===================
謝謝 christie 及 P.D. 兩位大大。

如以設 flag 欄位作判斷,我又想到一個問題,
當 A,B都同時停留在這一筆記錄查詢畫面,A動作快鎖定修改也作存檔,但B的畫面值沒有作同步,
那這種情況如何去解決呢,在修改時 畫面的值 和 資料庫的值 在一一比對,告訴B資料已被修改請重新作查詢動作。

請問各位大大,有什麼方法可解決。

麻煩大家。thks
t0288542
中階會員


發表:216
回覆:254
積分:94
註冊:2004-10-06

發送簡訊給我
#7 引用回覆 回覆 發表時間:2009-03-24 19:35:31 IP:60.248.xxx.xxx 訂閱
謝謝 christie 及 P.D. 兩位大大。

謝謝 建議我的資料及意見,想想要學東西真多,真是還要努力。

因為目前 公司內部 生產計劃 及 公司在庫,使用者原有的作業 方式 是以 Excel檔 設 共用,
所以會有多人去維護這一塊,可能會動到同一筆記錄,使用者異動記錄會很頻繁,
使用者希望可以看見最新資料。

我的想法是在放個 timer 一段時間,重新整理一下。不知是否ok.

麻煩大家,thks



RootKit
資深會員


發表:16
回覆:357
積分:419
註冊:2008-01-02

發送簡訊給我
#8 引用回覆 回覆 發表時間:2009-03-24 20:34:22 IP:122.126.xxx.xxx 訂閱
這個問題在 3-Tier 會很好解決。
定時刷新,這個量會太大。一般是用觸發器去解決,比較省時省力。
t0288542
中階會員


發表:216
回覆:254
積分:94
註冊:2004-10-06

發送簡訊給我
#9 引用回覆 回覆 發表時間:2009-03-26 13:50:20 IP:60.248.xxx.xxx 訂閱
謝謝您 RootKit  大大,

以往 對 3-Tier 學的是觀念,不知道怎麼去運用在 Delphi,
是否可以給我一個方向或者有個簡單範例,還是那本書對於初學者 去學習。

麻煩大家。thks
RootKit
資深會員


發表:16
回覆:357
積分:419
註冊:2008-01-02

發送簡訊給我
#10 引用回覆 回覆 發表時間:2009-03-26 14:37:10 IP:61.222.xxx.xxx 訂閱
3-Tier 最大優點在於 集中管理,可以很清楚每一個 Client 在作些什麼。

針對您的問題有兩點:
1. 多人同時修改紀錄。
2. 資料顯示同步。
因此在 3-Tier 是比較容易解決,可以在 AP SERVER 端處理。(當然暫時不考慮負載平衡,要做也可比較繁瑣。)
亦可模擬觸發器通知其他 Thread 即 Client。

針對資料顯示同步,我建議透過資料庫的觸發器 ( 2 or 3 Tier )處理。
jackiemi2_seed
中階會員


發表:33
回覆:94
積分:75
註冊:2006-09-11

發送簡訊給我
#11 引用回覆 回覆 發表時間:2009-04-01 16:40:58 IP:61.218.xxx.xxx 訂閱
id         name     addr 
0001 大毛 美國
id為pk欄位
把大毛修改成二毛,
update table_a set name='二毛' where id='0001' and name='大毛'
下指令儲存時把修改的欄位及pk欄位加入where條件,
這樣就可以避免有人先把資料修改了
但要記得判斷修改筆數是否為1,
powerbuild的datastore的update設定有這個選項可以選,滿利害的
不知delphi有沒有類似的東西
===================引 用 t0288542 文 章===================
請問各位大大,

如果遇到多個使用者 同時在維護某一表格時,如何去防止 當A或B,同時對某一筆記錄作修改時,
A,動作比較快,B再修改後存檔就會有問題,
"更新的資料列 最後讀取的值己被變更"

各位大大,有什麼方法可以作。

thks
------
OS : Win 7 pro
Program : Delphi 7
DataBase : Ms Sql 2008
P.D.
版主


發表:571
回覆:3880
積分:3666
註冊:2006-10-31

發送簡訊給我
#12 引用回覆 回覆 發表時間:2009-04-01 23:13:20 IP:61.67.xxx.xxx 未訂閱
以timer當然是可以的, 這是由client 各自發起的thread來重新 reload 資料庫, 但要注意的是, 要加入判斷目前pc正在做啥事的功能, 否則這台正在更新資料, 你的timer給 reflash 的話, 那使用者會出 "國罵" 的
===================引 用 t0288542 文 章===================
略....
我的想法是在放個 timer 一段時間,重新整理一下。不知是否ok.

麻煩大家,thks



pcplayer99
尊榮會員


發表:142
回覆:738
積分:591
註冊:2003-01-21

發送簡訊給我
#13 引用回覆 回覆 發表時間:2009-04-10 11:11:04 IP:116.24.xxx.xxx 訂閱
我在 Delphi - Midas  基础上来讨论这个问题。假设大家熟悉 Midas:

Midas,也就是后来的 DataSnap 架构,简单点说,就是 Delphi 提供的 3 层架构,类似这样的架构: Connection - DataSet - DataSetProvider --- 3层连接诸如 SocketServer 或者甚至是 WebService --- Client 端的 ClientDataSet --- Datasource --- DBGrid

在这个架构下,需要注意的观念是:客户端也就是 Client 端,每次从 SERVER 端取完数据后,就断开连接,是【非状态】的,也就是服务器端不保存客户端的状态。当然,MIDAS 也支持服务器端保存客户端的状态的方式,但这样的方式不好,客户端很多的时候,服务器端会压力很大。

在上述观念下,假设有 2 个客户端,都从服务器端取得了同一个 TABLE 的数据到客户端的 ClientDataSet 里,并显示到 DBGird 里,假设 DATA 如下:

ID Name Age

1 Jack 26
2 Rose 28


假设有这么两条 RECORD 同时在客户端 A 和客户端 B。假设 A 把 JACK 的 AGE 从 26 修改为 29; B 把 JACK 的 AGE 从 26 修改为 25。修改完后,当然要提交。这个时候,程序该如何处理?

这样的情况下,首先要考虑的是你的程序提供什么样的逻辑给用户。逻辑可能有多种,比如:
1. 以最后修改的为准;
2. 如果别人修改过了,必须看到最新的结果后,再考虑是否可以再次修改;
3. 如果别人已经修改过,则不能进行修改;

上面 3 种逻辑,都是可能的,看你采用哪一种。也许还有其它的逻辑规则呢,也说不定。看你的客户要求是什么了。

那上述假设里,A 和 B 就算同时按下提交按钮,也可能是 A 先提交,也可能是 B 先提交。不管谁先提交,后提交者面临一个问题:那条记录,在 DataBase 里面,AGE 已经和原来不一样了!

而 DELPHI 的 DataSnap 则提供了各种控制提交的可能。比如要实现逻辑 1,以最后修改的为准,如果按照 MIDAS 的默认设置,后提交者会提交失败的。因为默认设置,MIDAS 的 SERVER 端的 DataSetProvider 会去和 DataBase 里的同一条记录做比对,如果不同,则不会提交。会返回提交错误给客户端。按照逻辑 1,我需要不管那条记录是否已经被别人修改,都可以提交。那么,更改 DataSetProvider 的属性,设置为只以 Primary Key 为准,则 DataSetProvider 会从 DataBase 里用客户端提交记录的 Primary Key 来搜索那条记录,搜索到,则 Update 该记录,提交成功。

如果采用逻辑2,那么:
DataSetProvider 的默认属性,是以所有 Field 为条件去 select 该记录,后提交者提供的该记录的原始记录是 1, Jack, 26,而 DataBase 里该记录可能是 1, Jack, 28,那么,DataSetProvider 搜索不到正确的记录,就不会真正提交修改后的数据给 DataBase ,而会返回异常给客户端了。这时候,客户端可以在 clientDataSet 的 ReconcileError 事件里,进行相应的处理。比如提示用户该记录已经被修改过了,是否仍然要提交(也就是覆盖了前人的修改),还是放弃提交,等。

如果采用逻辑3,则仍然采用默认属性设置,提交失败则提示用户,然后直接放弃提交就可以了 --- 这里,放弃掉提交后,需要把用户当前的数据比如 1, Jack, 26 刷新为 DataBase 里最新的数据比如 1, Jack, 28,最简单的是 ClientDataSet.Refresh 一下。当然,为了效率,可以做得更复杂一些,仅仅是从 Server 端取回这一条记录。这里又涉及到其它一些 ClientDataSet 使用上的观念和技巧了。对于这些技巧,如果有需要,我们可以假设一种具体的案子,然后可以进一步讨论。


总之,搞清楚 MIDAS 的工作原理,就很容易想到类似情况该如何处理了。搞清楚的办法,我比较笨,是在提交的时候,直接设置断点,跟踪 DataSetProvider 内部的代码,看它每一步是如何处理的。

===================引 用 P.D. 文 章===================
以timer當然是可以的, 這是由client 各自發起的thread來重新 reload 資料庫, 但要注意的是, 要加入判斷目前pc正在做啥事的功能, 否則這台正在更新資料, 你的timer給 reflash 的話, 那使用者會出 "國罵" 的
===================引 用 t0288542 文 章===================
略....
我的想法是在放個 timer 一段時間,重新整理一下。不知是否ok.

麻煩大家,thks


系統時間:2017-10-20 23:52:21
聯絡我們 | Delphi K.Top討論版
本站聲明
1. 本論壇為無營利行為之開放平台,所有文章都是由網友自行張貼,如牽涉到法律糾紛一切與本站無關。
2. 假如網友發表之內容涉及侵權,而損及您的利益,請立即通知版主刪除。
3. 請勿批評中華民國元首及政府或批評各政黨,是藍是綠本站無權干涉,但這裡不是政治性論壇!