1回のトランザクションで複数回データベースの更新を行う箇所があり、どうしても256件以上の更新を行う可能性があります。
Paraoxを使用しているのですが、255レコードまでは変更できるということはヘルプから判明しましたが、256レコード以上になるとやはりできませんでした。
これをできるようにする方法は何かあるのでしょうか。
Delphi7(Pro)+Paradoxでの環境です。
うるおぼえモードですが。。。
トランザクション前にLockTable
トランザクション後にUnLockTable
だったような気が(??)
通りすがりさん、早速のアドバイスありがとうございます。
ご指摘の LockTable、UnLocktable を使用してみたのですが
やはり256件目でエラーとなってしまうようです。
以下にその部分の抜粋を置きますので、なんかおかしいところが
あれば、ご指摘ください。
例)単純なUPDATE文 'UPDATE TEST Set Item = :PItem WHERE Key = :PKey ;' を256回繰り返す部分の抜粋
procedure AThread.AProc ;
var
cnt: Integer;
begin
Table1.Open;
Table1.LockTable(ltWriteLock);
Database1.TransIsolation := tiDirtyRead;
Database1.StartTransaction;
try
for cnt := 0 to 256 do
begin
// ↓Query1(TQuery)にはSQLをセットしておきパラメータ
// を変更して使用しています。
Query1.close;
Query1.ParamByName('PItem').AsString := 'Item';
Query1.ParamByName('PKey').AsInteger := cnt;
// ↓256件目でエラー
Query1.ExecSQL;
end;
Database1.Commit;
Table1.UnLockTable(ltWriteLock);
Table1.Close;
except
マニュアルを見ると
「最大ロック数の制限を越えるにはキャッシュアップデートしろ」
とありますね。
Queryですか?
てっきり、以下のようなことを想定していました。
procedure AThread.AProc ;
var
cnt: Integer;
begin
Table1.Open;
Table1.LockTable(ltWriteLock);
Database1.TransIsolation := tiDirtyRead;
Database1.StartTransaction;
try
{
for cnt := 0 to 256 do
begin
// ↓Query1(TQuery)にはSQLをセットしておきパラメータ
// を変更して使用しています。
Query1.close;
Query1.ParamByName('PItem').AsString := 'Item';
Query1.ParamByName('PKey').AsInteger := cnt;
// ↓256件目でエラー
Query1.ExecSQL;
end;
}
for cnt:=0 to 999 do
begin
Table1.EditKey;
Table1.FieldByName('Key').AsInteger := cnt;
if Table1.GotoKey then
begin
Table1.Edit;
Table1.FieldByName('Item').AsString := 'Item';
Table1.Post;
end;
end;
Database1.Commit;
Table1.UnLockTable(ltWriteLock);
Table1.Close;
except
Database1.Rollback;
Table1.UnLockTable(ltWriteLock);
Table1.Close;
end;
end;
私もDelphi7 + Paradoxで開発していますがキャッシュアップデートを使っています。
procedure AThread.AProc ;
var
cnt: Integer;
begin
Table1.Open;
Table1.LockTable(ltWriteLock);
// キャッシュアップデート開始
Query1.CachedUpdates := True;
for cnt := 0 to 256 do
begin
Query1.close;
Query1.ParamByName('PItem').AsString := 'Item';
Query1.ParamByName('PKey').AsInteger := cnt;
Query1.ExecSQL;
// 書き込んだ内容はキャッシュされ実際のテーブルには保存されない。
end;
Database1.StartTransaction;
try
Query1.ApplyUpdates; // キャッシュした内容を書き込み
Database1.Commit;
except
Database1.Rollback;
raise;
end;
Query1.CommitUpdates; // キャッシュを空にする
Query1.CachedUpdates := False;
Table1.Close;
end;
てな感じかな。
詳しくは、ヘルプでApplyUpdatesなどを検索してみてください。
※.机上コーディングなので間違えがあったらごめんなさい。
回答をいただいた皆様、アドバイスありがとうございます。
Queryだと、処理的に難しいんでしょうか?
処理速度が要求されてしまうので、Query を使用しています。
Table ごとの処理だと Query 使用時よりたくさん時間がかかるといわれたので・・・
皆様からのご指摘事項は実際の開発要員へ確認させています。(私自身は営業的な
立場なので・・・)
いろいろ試してみたいので、皆様、どうぞよろしくお願いいたします。
本題とはずれてしまいますが、素朴な疑問を1つ。
>処理速度が要求されてしまうので、Query を使用しています。
>Table ごとの処理だと Query 使用時よりたくさん時間がかかるといわれたので・・・
とありますが、
例からすると257回もQueryを投げていますよね。
ループ処理になってしまう部分をQueryを使用することで、
1回なり少ない回数を投げてデータベース側に処理をお任せするんだと思うのですが。
単なる例ならば、どうでもいいんですけど。
失礼しました。
masayanさんからご指摘いただいたキャッシュアップデートの方法を試してみたところ、ApplyUpdates の個所でエラーが発生してしまいました。
"データセットが編集または挿入モードではありません"というエラーとなってしまうのです。
恐らくは ApplyUpdates を発行する前に何らかのモード切替処理が必要になるのだろう、と思っているのですが、よくわかりません。
ご存知の方、教えてください!
せいにゃさん、ごめんなさい。
TQueryのExecSQL(SQLのUPDATE)によるレコード更新はキャッシュアップデートが効かないようです。
キャッシュアップデートは、データセットに対する更新や追加データをキャッシュしますが、ExecSQLでは、UPDATEやINSERTなどだけが実行されるとは限らないためだと思われます。(自分も昔、同じことでやった記憶が...)
できるのであればQuery1をTTableに変更できませんか?
例えば、変更処理を以下のようしてください。
for cnt := 0 to 256 do
begin
if Table2.Locate(....) then // 変更対象の検索
begin
Table2.Edit;
Table2.ParamByName('PItem').AsString := 'Item';
Table2.ParamByName('PKey').AsInteger := cnt;
Table2.Post;
end;
end;
皆様、お世話になっております。
いろいろ有意なご意見をありがとうございました。
1トランザクション中での更新件数を削減する方向で
修正をはじめました。ご指摘いただいた TTable につきましては
開発サイドでのノウハウ及び経験を考慮し、別手段にて回避するように
したようです。
時間はかかるかもしれませんが、なんとか解決の糸口が見えてきたような
感じです。
今まで、参考になるご意見をいただきました、
通りすがりさん、えびさん、masayanさん、本当にありがとうございました。
今後もよろしくお願いいたします。
ツイート | ![]() |