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

多個執行緒Thread用dbExpress元件存取資料庫之交易管理問題

尚未結案
apl
一般會員


發表:5
回覆:4
積分:1
註冊:2003-04-08

發送簡訊給我
#1 引用回覆 回覆 發表時間:2003-12-26 18:49:43 IP:61.231.xxx.xxx 未訂閱
(* 說明: 以下程式表示每個Thread持續自資料庫讀取屬於該用戶之最早10筆資料並加以處理。每個用戶會有2個以上之Thread, 要求Thread在讀取資料時, 不可重複讀取同一用戶之其它Thread正在處理之資料。    作業環境: Delphi7.0(on Windows2000 sp3) + MS SQL Server 2000(on Windows2000 sp3)    DB元件: dbExpress元件如下:         dbxconn: TSQLConnection;         dbxq: TSQLquery;         dbxsds: TSimpleDataSet;    程式碼: 如下 *) procedure TMsgThread.ThreadProc; var   sSql: string;   aTD: TTransactionDesc;   i, noMsg, nLen, myId: Integer;   m: array[0..9] of TRecordMsg; // msg array   binData: array of Byte; // byte array   bProcessMsgOk: Boolean; begin      bProcessMsgOk := False;   noMsg := 10;      // 產生一組亂數(亂數值避開0/1), 用以鎖定資料    Randomize;   myId := Random(32757) + 10; // 10<=myId<32767 // 第一階段交易: 選定訊息 aTD.TransactionID := 1; aTD.IsolationLevel := xilDIRTYREAD; dbxconn.StartTransaction(aTD); try sSql := Format('select top %d * from TBL_MSG' ' where (USER_ID=%d) and (MSG_STATUS=0)' ' order by TIME_RECEIVED', [noMsg, FUserId]); with dbxq do begin Close; SQL.Text := Format('update TBL_MSG set MSG_STATUS=%d ' 'from (%s) as T1 where (TBL_MSG.MSG_ID=T1.MSG_ID)', [myId, sSql]); ExecSQL(True); Close; end; dbxconn.Commit(aTD); except dbxconn.Rollback(aTD); raise; end; // 第二階段交易: 處理選定訊息 aTD.TransactionID := 1; aTD.IsolationLevel := xilREADCOMMITTED; dbxconn.StartTransaction(aTD); try sSql := Format('select * from TBL_MSG' ' where (USER_ID=%d) and (MSG_STATUS=%d)' ' order by TIME_RECEIVED', [FUserId, myId]); with dbxsds do begin Active := False; PacketRecords := noMsg; DataSet.CommandText := sSql; Active := True; if (RecordCount > 0) then begin First; for i := 0 to (noMsg - 1) do begin if eof then break; // 讀出資料長度及內容 m[i].len := FieldValues['MSG_LENGTH']; binData := FieldValues['MSG_BINDATA']; CopyMemory(@m[i].binData[0], @binData[0], m[i].len); // 修改訊息狀態 Edit; FieldByName('MSG_STATUS').Value := 1; //設為已處理完畢 Next; end; ApplyUpdates(0); Active := False; end //if (RecordCount > 0) else bProcessMsgOk := True; // 無訊息待處理 end; // with { 在此處理讀入之資料 ... ... ... ... } bProcessMsgOk := True; // 表示第一階段鎖定資料已處理完畢 dbxconn.Commit(aTD); except dbxconn.Rollback(aTD); end; // 第三階段: 若第二階段處理失敗 if not bProcessMsgOk then begin aTD.TransactionID := 1; dbxconn.StartTransaction(aTD); try sSql := Format( ' update TBL_MSG set MSG_STATUS=0 ' ' where (USER_ID=%d) and (MSG_STATUS=%d)', [FUserId, myId]); with dbxq do begin Close; SQL.Text := sSql; ExecSQL(True); Close; end; dbxconn.Commit(aTD); except dbxconn.Rollback(aTD); raise; end; end; // if not bProcessMsgOk end; //---------------------------------------------------------------- 目前作法分三階段: 第一階段:先選定10筆資料,加上亂數標記(避免其它Thread讀取) 第二階段:讀入上述標記資料進行處理。 第三階段:若第二階段處理失敗,則恢復第一階段選定的資料。 有幾個問題: 一、若不幸同時某用戶2個以上Thread選到同一組亂數,則第二階段就出問題。 (此題可自資料庫再次查詢便可確認無重複亂數) 二、若程式中第二階段處理失敗,將進入第三階段時程式掛了,則這些資料 便無法恢復成原來狀態。(此題很難解) 不知大家有沒有辦法將上述三階段合併在一個交易中完成?
系統時間:2024-07-01 9:17:40
聯絡我們 | Delphi K.Top討論版
本站聲明
1. 本論壇為無營利行為之開放平台,所有文章都是由網友自行張貼,如牽涉到法律糾紛一切與本站無關。
2. 假如網友發表之內容涉及侵權,而損及您的利益,請立即通知版主刪除。
3. 請勿批評中華民國元首及政府或批評各政黨,是藍是綠本站無權干涉,但這裡不是政治性論壇!