IBXのトランザクションエラー

解決


印刷屋  2008-01-07 03:27:51  No: 29174

たびたび失礼します。
Delete文は無事通るようになったのですが、同じような処理でCommitしたときに
「トランザクションが有効でありません。」
となります。
データは保存されています。

IBTransaction.StartTransaction;
try
  with IBQuery do
  begin
    SQL.Clear;
    SQL.LoadFromFile(Select文);
    Open;
    if Locate('CODE',edtCode.Text,[])then begin
      Close;
      SQL.Clear;
      SQL.LoadFromFile(UpDate文);
    end else begin
     Close;
     SQL.Clear;
     SQL.LoadFromFile(Insert文);
    end;
    
    //パラメータ入力
    ParamByName('CODE').AsString := edtCode.Text;
    ParamByName('…
    ExecSQL;
  end;
  IBTransaction.Commit;//ここを通過するとエラー
except
  IBTransaction.RollBack;
  raise;
end;

なるべくトランザクションは手続き内で終了させてるはずなんですが。


印刷屋  2008-01-07 03:34:28  No: 29175

↑追加&更新処理に関する質問です。

Insert文やUpDate文はIBDataSetのエディターを流用して作ったので問題ないはずです。


igy  2008-01-07 05:08:23  No: 29176

IBQueryのTransaction プロパティには、IBTransactionが設定されてますか?


印刷屋  2008-01-07 07:28:57  No: 29177

されてます。

IBTransaction-IBDataBase-IBQueryの1セットを
をSQL文を書き換えて流用しています。


igy  2008-01-07 08:09:54  No: 29178

あと、
IBTransactionの DefaultDatabase プロパティには、IBDataBaseが指定されていますか?
また、
IBTransaction.StartTransaction;
のあと、
IBTransactionのInTransaction プロパティはtrueになってますか?


印刷屋  2008-01-07 09:44:49  No: 29179

ご指摘ありがとうございます。
  if IBTransaction.InTransaction then ShowMessage('OK');
をいろんな行に突っ込んでいったら、SQL文交換前のClose;で引っかかりました。
DataSetのClose;はトランザクション終わらせるんですか?
でも、トランザクションがスタートしたあとに同じようにSQL文を交換したDelete文は上手く通ってるんですよ。


DEKO  2008-01-07 12:00:46  No: 29180

> でも、トランザクションがスタートしたあとに同じように
> SQL文を交換したDelete文は上手く通ってるんですよ。
ソースを見た訳ではないので的外れかも知れませんが、Delete文の場合にはOpenしていないのではないでしょうか?私なら複数のTIBQueryを用いて以下のように書きます。

var
  Flg: Boolean;
begin
  IBTransaction.StartTransaction;
  try
    with IBQuery1 do
      begin
        SQL.LoadFromFile(Select文);
        Open;
        Flg := Locate('CODE',edtCode.Text,[]); 
        Close;
      end;

    with IBQuery2 do
      begin
        if Flg then 
          SQL.LoadFromFile(UpDate文);
        else 
          SQL.LoadFromFile(Insert文);
        //パラメータ入力
        ParamByName('CODE').AsString := edtCode.Text;
        ParamByName('…
        ExecSQL;
      end;
    IBTransaction.Commit;
  except
    IBTransaction.RollBack;
    raise;
  end;
end;

# 本当はLocateを使わずにSQLのWhere句で処理したい所ですけどね。


DEKO  2008-01-07 12:02:19  No: 29181

誤: SQL.LoadFromFile(UpDate文);
正: SQL.LoadFromFile(UpDate文)


印刷屋  2008-01-07 17:14:53  No: 29182

Delete文ではOpen→Close;はないです。

Locateを使わずにInsertとUpdateを切り分ける方法があるんですか?
すごく興味あります。


DEKO  2008-01-07 17:34:35  No: 29183

>Locateを使わずにInsertとUpdateを切り分ける方法があるんですか?

1.Where句でレコードがユニークになる条件を書いてレコードを特定。
2.Select文に"Select Count(*) From 〜"を指定して、Fields[0].AsIntegerを参照。
  値が0ならば該当レコードなし、1ならば該当レコードあり。
2'.TIBQuery.IsEmptyを参照。
  Trueならば該当レコードなし、Falseなら該当レコードあり。

レコードの存在を知るだけなら、上記いずれかが簡単です。
レコード数の多いDBではカレントの移動がない分だけ、高速に処理できます。

TIBQuery.RecordCountを調べる方法もありますが、Last/Firstをしないと
正常に件数が取得できない事が多く、カレントの移動が発生するので時間も掛かります。

# この辺は実際に試してみる事をオススメします。


印刷屋  2008-01-07 21:06:29  No: 29184

IsEmptyを分岐に使ったんですが、やっぱり同じ結果です。
SQL文を交換する以上、IsEmptyにしろFieldsにしろOpenCloseが1回入りますよね。
やっぱりこの処理が問題なんですかね。
StartTransactionをSQL入れ替え直後に下げたら一応トランザクションが通りました。

当面これでごまかそうと思ってますが、競合対策も考えねばと思ってます。
Osamu'sSquareの記事を見たりしてたんですけど、トランザクションのパラメータでテーブルをロックするか、ロックもどきのフィールドを追加するしかなさそうなんですが、
編集中のレコードのみをロックするのは、どういう風なのがあるんでしょうか?


※返信する前に利用規約をご確認ください。

※Google reCAPTCHA認証からCloudflare Turnstile認証へ変更しました。






  このエントリーをはてなブックマークに追加