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

ADO BatchUpdate 模式下更新 Other Table 的問題

答題得分者是:Chance36
bestlong
站務副站長


發表:126
回覆:734
積分:512
註冊:2002-10-19

發送簡訊給我
#1 引用回覆 回覆 發表時間:2004-05-24 17:31:58 IP:211.22.xxx.xxx 未訂閱
在 Master/Detail 關聯的狀況下, 常常會再去異動其他 Table 例如出貨單存檔時會去更新客戶的最新交易日期, 而明細異動會去更新庫存的數量,這樣在出貨單本身會以 transation 來保證交易的完整性, 但是在明細異動時要去更新 M/D Table 以外的其他 Table 時是使用 adoCommamd 處理, 這樣就不算在 transation 的範圍內了, 不知道技術上該如何處理的呢? 我是雪龍
------
http://blog.bestlong.idv.tw/
http://www.bestlong.idv.tw/
http://delphi-ktop.bestlong.idv.tw/
Chance36
版主


發表:31
回覆:1033
積分:792
註冊:2002-12-31

發送簡訊給我
#2 引用回覆 回覆 發表時間:2004-05-24 19:17:20 IP:211.20.xxx.xxx 未訂閱
bestlong 你好
  你必須將所有的更新作業,自行啟動並包在同一個交易控管的範圍內      If Not AdoConnection1.InTransaction Then
    AdoConnection1.BeginTrans; // 開始交易控管      Try
    // 更新MasterTable及detailTbale
    ADODataSet1.UpdateBatch([arAll]);
    ......
    // 更新 其他 Table
    AdoConnection1.CommitTrans; // 沒問題完成交易
  Except
    AdoConnection1.RollbackTrans; // 有問題則全部還還原
  End;
 
發表人 - chance36 於 2004/05/24 19:20:25
bestlong
站務副站長


發表:126
回覆:734
積分:512
註冊:2002-10-19

發送簡訊給我
#3 引用回覆 回覆 發表時間:2004-05-24 23:02:07 IP:61.59.xxx.xxx 未訂閱
Chance36 你好 關於您說的部份也就是我市面上的相關書籍得到的觀念,只是我還有疑惑? 目前我的做法 DBNavegater 是自己用 Botton 打造,其中 btnSave 內就如您的做法,當然 adoqyMaster 與 adoqyDetail 都設定 BatchUpdate 的模式,所以單就此兩個 Query 所 select 的相關 Table, 將異動資料時都會先 Cache 在 Client, 然後才在 btnSave 內包在 Transation 內同時更新至 Server。 而我的疑惑就是在處理 adoqyDetail 的時候,以出貨單舉例來說出貨單明細每增加一筆記錄就要去改變庫存檔的數量,我會在 adoqyDetail.AfterPost 事件中再運用一個 adoQuery 或 adoCommand 去異動庫存Table, 在這個部份我就覺得很疑惑,好像是已經完成庫存數的更新,而出貨單還在 Cache 當中,這樣不就喪失了 BatchUpdate 的意義? 我是雪龍
------
http://blog.bestlong.idv.tw/
http://www.bestlong.idv.tw/
http://delphi-ktop.bestlong.idv.tw/
Chance36
版主


發表:31
回覆:1033
積分:792
註冊:2002-12-31

發送簡訊給我
#4 引用回覆 回覆 發表時間:2004-05-24 23:14:54 IP:211.20.xxx.xxx 未訂閱
引言: 而我的疑惑就是在處理 adoqyDetail 的時候,以出貨單舉例來說出貨單明細每增加一筆記錄就要去改變庫存檔的數量,我會在 adoqyDetail.AfterPost 事件中再運用一個 adoQuery 或 adoCommand 去異動庫存Table, 在這個部份我就覺得很疑惑,好像是已經完成庫存數的更新,而出貨單還在 Cache 當中,這樣不就喪失了 BatchUpdate 的意義?
以你這種做法,是會有這種現象很正常的,問題是你希望連庫存Table也要與M/D Table一起有BatchUpdate 效果,那必須同樣的用TAdoQuery並設定為BatchUpdate 模式才可以。
bestlong
站務副站長


發表:126
回覆:734
積分:512
註冊:2002-10-19

發送簡訊給我
#5 引用回覆 回覆 發表時間:2004-05-25 00:52:52 IP:61.59.xxx.xxx 未訂閱
引言: 以你這種做法,是會有這種現象很正常的,問題是你希望連庫存Table也要與M/D Table一起有BatchUpdate 效果,那必須同樣的用TAdoQuery並設定為BatchUpdate 模式才可以。
因為是要把原來的程式改成 BatchUpdate Transation 的更新方式來減少資料庫 Lock 以及資料異動不完整的問題,所以才會面臨到這個問題,而市面上的書籍都沒看到這方面的資料,Client/Server 架構的程式真的要想很多,真的很想趕快搞清楚如何處理才是面面俱到。不然總是要擔心資料何時會顯現出隱藏的問題 我是雪龍
------
http://blog.bestlong.idv.tw/
http://www.bestlong.idv.tw/
http://delphi-ktop.bestlong.idv.tw/
Chance36
版主


發表:31
回覆:1033
積分:792
註冊:2002-12-31

發送簡訊給我
#6 引用回覆 回覆 發表時間:2004-05-25 02:12:31 IP:203.204.xxx.xxx 未訂閱
bestlong 你好 不同的資料更新方式,各有其優缺點及其適用時機,以你的狀況來看,個人覺得使用BatchUpdate模式,應該會有問題,因為BatchUpdate模式適用於每個人操作的資料範圍,最好不要有重疊,或有少許的資料重疊,但可以用程式碼簡單的予以避免掉,以防止破壞資料的完整性或正確性。而你的庫存Table(應該是與庫存量相關的更新)要與M/D Table 一起BatchUpdate,那麼在更新前,有異動到的庫存資料已被別人早一步更新過了,此時則該如何是好呢? 或許你可以想一套處理更新不成功時的調整處理邏輯,以解決這個問題,以此狀況來說,如果是我,我會在作業流程(或程式的流程)上來解決: 1.M/D Table在同一交易中先行儲存(若每人處理的資料互不衝突,則交易管理亦可以省了) 2.在主檔及明細檔中設置一個[已過帳]欄位以作為程式異常後,若要繼續處理時,判斷己處理及未處理的依據從而避免資料的重複過帳。 3.開啟一個交易,開始作過帳的動作,明細檔做完一筆,將該筆[已過帳]欄位設為True,同一筆主檔的明細資料全部作完後,則將主檔的該筆[已過帳]欄位設為True,直到全部完成為止。 4.在[存檔]的動作中,單據的儲存及庫存資料的更新先後完成(先確定單據的儲存動作完成,才能作庫存資料的更新),對於使用者來說,仍是一個動作。 如此下來,主檔明細檔的批次更新與庫存Table的更新分隔開來,以程式面來看是不是可以簡化了(不用同時考慮庫存的更新),而庫存Table的更新也可以在短時間內更新完成,縮短資料鎖定的時間,重點是若要作表單審核的需求時,庫存的更新動作正好可以放到審核的動作中來完成。 PS:以上純屬個人看法,僅供參考。
bestlong
站務副站長


發表:126
回覆:734
積分:512
註冊:2002-10-19

發送簡訊給我
#7 引用回覆 回覆 發表時間:2004-05-25 09:55:01 IP:211.22.xxx.xxx 未訂閱
Chance36 你好    您的說明真的很寶貴, 在此先謝謝您提供指導。    
引言: 不同的資料更新方式,各有其優缺點及其適用時機,以你的狀況來看,個人覺得使用BatchUpdate模式,應該會有問題,因為BatchUpdate模式適用於每個人操作的資料範圍,最好不要有重疊,或有少許的資料重疊,但可以用程式碼簡單的予以避免掉,以防止破壞資料的完整性或正確性。而你的庫存Table(應該是與庫存量相關的更新)要與M/D Table 一起BatchUpdate,那麼在更新前,有異動到的庫存資料已被別人早一步更新過了,此時則該如何是好呢? 或許你可以想一套處理更新不成功時的調整處理邏輯,以解決這個問題,以此狀況來說,如果是我,我會在作業流程(或程式的流程)上來解決: 1.M/D Table在同一交易中先行儲存(若每人處理的資料互不衝突,則交易管理亦可以省了) 2.在主檔及明細檔中設置一個[已過帳]欄位以作為程式異常後,若要繼續處理時,判斷己處理及未處理的依據從而避免資料的重複過帳。 3.開啟一個交易,開始作過帳的動作,明細檔做完一筆,將該筆[已過帳]欄位設為True,同一筆主檔的明細資料全部作完後,則將主檔的該筆[已過帳]欄位設為True,直到全部完成為止。 4.在[存檔]的動作中,單據的儲存及庫存資料的更新先後完成(先確定單據的儲存動作完成,才能作庫存資料的更新),對於使用者來說,仍是一個動作。 如此下來,主檔明細檔的批次更新與庫存Table的更新分隔開來,以程式面來看是不是可以簡化了(不用同時考慮庫存的更新),而庫存Table的更新也可以在短時間內更新完成,縮短資料鎖定的時間,重點是若要作表單審核的需求時,庫存的更新動作正好可以放到審核的動作中來完成。 PS:以上純屬個人看法,僅供參考。
在存檔功能採用先儲存後過帳的方式(在單據[存檔]的功能中處理)來從資料異動的角度來思考的話: 1.[新增]目前是想不出會有何問題,因為一定是未過帳記錄。只是單據若是已完成過帳就不得再新增,若一定要新增的話必須先把主檔取消過帳後再新增。 2.[修改]如果是先存檔後才更新其他相關Table,這樣就要保存紀錄的原始值先做復原然後再依據新的值來更新 3.[刪除]一樣要保存被刪除的紀錄,以作為更新其他資料的依據 感覺起來若是這樣處理變的很複雜 我是雪龍 發表人 - bestlong 於 2004/05/25 10:03:54
------
http://blog.bestlong.idv.tw/
http://www.bestlong.idv.tw/
http://delphi-ktop.bestlong.idv.tw/
Chance36
版主


發表:31
回覆:1033
積分:792
註冊:2002-12-31

發送簡訊給我
#8 引用回覆 回覆 發表時間:2004-05-26 04:01:06 IP:203.204.xxx.xxx 未訂閱
引言: 感覺起來若是這樣處理變的很複雜
bestlong 你好 程式複不複雜,這是個見仁見智的問題,端看你以什麼角度來審視這個問題,而你的取決點又在那裏?之前的論述是配合你的問題需求提出來的,或許沒有想的很周詳(畢竟不是我切身的問題,好像有點不負責任喔!討論不就是這樣嗎?)沒辦法,因為問題是這樣所以回答就會這樣。 任何的取捨都會有得有失,只是看得到的多還是失去的多;每個人的經歷、經驗與體會各有不同,也許你認為很簡單的而我認為很難,也許你認為很難的我卻認為很簡單,所以每個人最後的決定會有所不同;而同樣的做法,對你或許是得到的多,但對我可能是失去的多。無論如何取捨,總是要能够有完整的解決方案才是吧!。 < class="code"> 想了又想還真有點複雜,好像回到起點來還比較好點,再重貼一遍,並稍作修改 If Not AdoConnection1.InTransaction Then AdoConnection1.BeginTrans; // 開始交易控管 Try // 主檔明細未更新前先更新 其他 Table While Not MasterTable.Eof Do Begin While Not DetailTable.Eof Do Begin // 更新 其他 Table // 因為這裏才可抓到主檔及明細檔的異動狀態、更新前及更新後的值,來加以運算庫存Table的更新值 // 如果是新增=>只要直接過帳即可 // 如果是修改=>用新的值-舊值的結果來過帳(其實就是用舊值反過帳,用新值過帳) // 如果是刪除=>只要直接反過帳即可 DetailTable.Next; End; MasterTable.Next; End; // 最後才更新MasterTable及detailTbale ADODataSet1.UpdateBatch([arAll]); ...... AdoConnection1.CommitTrans; // 沒問題完成交易 Except AdoConnection1.RollbackTrans; // 有問題則全部還還原 End; 發表人 - chance36 於 2004/05/26 04:04:36
bestlong
站務副站長


發表:126
回覆:734
積分:512
註冊:2002-10-19

發送簡訊給我
#9 引用回覆 回覆 發表時間:2004-05-26 10:44:54 IP:211.22.xxx.xxx 未訂閱
Chance36 你好:    您說的沒錯, 正是因為要尋求完整的解決方案, 任何的建議與想法, 無論是簡單或是複雜都要用同一套高標準來檢視, 並不斷加入新的要求與限制, 我也常常回到原點重新思考所追求的目標, 從單機資料庫轉換到C/S兩層架構要考量的問題多了很多, 其實也只是要達到: 1. 為了資料的完整性, 所有的異動都要在一個交易內完成. 2. 為了減少 Lock 的發生, 這個交易的處理時間要越短越好. 不知在觀念上, 是否還有遺漏.
引言:
  If Not AdoConnection1.InTransaction Then
    AdoConnection1.BeginTrans; // 開始交易控管      Try
    // 主檔明細未更新前先更新 其他 Table
    While Not MasterTable.Eof Do Begin
      While Not DetailTable.Eof Do Begin
        // 更新 其他 Table
        // 因為這裏才可抓到主檔及明細檔的異動狀態、更新前及更新後的值,來加以運算庫存Table的更新值
        // 如果是新增=>只要直接過帳即可
        // 如果是修改=>用新的值-舊值的結果來過帳(其實就是用舊值反過帳,用新值過帳)
        // 如果是刪除=>只要直接反過帳即可
        DetailTable.Next;
      End;
      MasterTable.Next;
    End;
    
    // 最後才更新MasterTable及detailTbale
    ADODataSet1.UpdateBatch([arAll]);        ......
    AdoConnection1.CommitTrans; // 沒問題完成交易
  Except
    AdoConnection1.RollbackTrans; // 有問題則全部還原
  End;
這樣的做法正是我所要的, 只是您採用巢狀 While 是否為達到可以異動多筆單據後在一次交易中全部更新, 這樣在多人環境下會提高所異動的資料, 已被他人異動的衝突, 所以我會採取一張單據一個交易的方式, 也就是拿掉 While Not MasterTable.Eof Do Begin 這個迴圈. 我是雪龍
------
http://blog.bestlong.idv.tw/
http://www.bestlong.idv.tw/
http://delphi-ktop.bestlong.idv.tw/
bestlong
站務副站長


發表:126
回覆:734
積分:512
註冊:2002-10-19

發送簡訊給我
#10 引用回覆 回覆 發表時間:2004-05-26 11:03:34 IP:211.22.xxx.xxx 未訂閱
引言: 這樣的做法正是我所要的, 只是您採用巢狀 While 是否為達到可以異動多筆單據後在一次交易中全部更新, 這樣在多人環境下會提高所異動的資料, 已被他人異動的衝突, 所以我會採取一張單據一個交易的方式, 也就是拿掉 While Not MasterTable.Eof Do Begin 這個迴圈.
在仔細想了想, 這樣的說法好像會出問題, 因為 Detail 的資料是配合 Master 的, 所以在尚未更新回資料庫的狀態下, Master 移動了 Curser 就會讓 Detail 重新取得關聯的資料, 而導致先前 Detail 的異動資料遺失. 不知道這樣的觀念是否正確? 以下就是修改後的 Code
  If Not AdoConnection1.InTransaction Then
    AdoConnection1.BeginTrans; // 開始交易控管      Try
  // 主檔明細未更新前先更新 其他 Table
    While Not DetailTable.Eof Do Begin
      // 更新 其他 Table
      // 因為這裏才可抓到主檔及明細檔的異動狀態、更新前及更新後的值,來加以運算庫存Table的更新值
      // 如果是新增=>只要直接過帳即可
      // 如果是修改=>用新的值-舊值的結果來過帳(其實就是用舊值反過帳,用新值過帳)
      // 如果是刪除=>只要直接反過帳即可
      DetailTable.Next;
    End;
    
    // 最後才更新MasterTable及detailTbale
    ADODataSet1.UpdateBatch([arAll]);        ......
    AdoConnection1.CommitTrans; // 沒問題完成交易
  Except
    AdoConnection1.RollbackTrans; // 有問題則全部還原
  End;
另外在修改的狀況下, 用新值 - 舊值的說明方式較為不妥. 因為我曾發生因為這樣的註解誤導了自己只考慮到數量欄位部份, 確沒想到舊的紀錄與新的紀錄是不一樣的商品, 想當初為了找出原因真的花了很久的時間. 我是雪龍 發表人 - bestlong 於 2004/05/26 11:07:19
------
http://blog.bestlong.idv.tw/
http://www.bestlong.idv.tw/
http://delphi-ktop.bestlong.idv.tw/
bestlong
站務副站長


發表:126
回覆:734
積分:512
註冊:2002-10-19

發送簡訊給我
#11 引用回覆 回覆 發表時間:2004-06-10 16:15:08 IP:211.22.xxx.xxx 未訂閱
如果開發的程式只會運用在 Client/Server 的架構下, 而且所使用的資料庫具有 Trigger 的能力, 可以把異動相關 Table 的作業, 寫在 Stored Procedure 配合 Trigger 來做 Insert/Update/Delete 處理. 也是一個好方法 我是雪龍
------
http://blog.bestlong.idv.tw/
http://www.bestlong.idv.tw/
http://delphi-ktop.bestlong.idv.tw/
系統時間:2024-07-01 17:30:12
聯絡我們 | Delphi K.Top討論版
本站聲明
1. 本論壇為無營利行為之開放平台,所有文章都是由網友自行張貼,如牽涉到法律糾紛一切與本站無關。
2. 假如網友發表之內容涉及侵權,而損及您的利益,請立即通知版主刪除。
3. 請勿批評中華民國元首及政府或批評各政黨,是藍是綠本站無權干涉,但這裡不是政治性論壇!