トランザクション中に任意のテーブル更新だけ先にCommitを確定させたい。
こんにちは、皆さま。
業務でIRISを用いて開発を行っている者です。
現在テーブルを用いてシステムの設計を行っておりますが、
トランザクション中に、そのトランザクションの影響を受けずにテーブルを
更新するような仕組みが欲しいと考えております。
(トランザクションがRollbackされても、そのテーブルの更新だけは確定させたい。)
例えば$INCREMENT()はトランザクション中であっても、その制約を無視して値を更新できます。
そのような回避策がないかをご教示いただきたいです。
用途としては、連番を生成するAPIを作成していて、その値をテーブルで管理しています。
このAPIは複数プロセスから呼ばれることがありますが、
1トランザクション中の連続Updateにより、行ロックからテーブルロックへの昇格が行われる
(1000行以上行ロックをしたときのIRISの仕様)ことで、
他プロセスがAPIを利用できなくなるなどの影響が出ています。
今回のAPIに関しては、番号重複さえ起きなければよいので、そのような影響は受けたくありません。
極力グローバルは用いない設計としたいので、テーブルで対応したいです。
すいませんが、何か情報をお持ちの方はご回答いただけますと幸いです。
Comments
Ohataさん、
こんにちは。
ちょっと調べてみたのですが、
UPDATE文に%NOJOURNというオプションがありますので
UPDATE %NOJOURN table SET counter = counter + 1 WHERE name='xxx'
のように記述いただくと、その更新はロールバックを無視します。
よろしくお願いします。
Minamoto さん
ご回答いただきありがとうございます!
記載頂いたものについては、私が欲していたものなのですが、
よくよく考えるとミラーリングを行っている都合上、
ジャーナルに書かれないデータが出来てしまう事にリスクを感じています。
($INCREMENTもそうでしたね。。。)
そのため、わがままな要望となってしまい大変恐縮なのですが、
ジャーナルには書かれるが、親のトランザクションを無視して更新を確定させたいです。
IRISの仕組み的に難しそうでしょうか・・・?
Ohataさん
こんにちは。
残念ながら、ミラーリングですと、%NOJOURNキーワードは無視されるようです。
その他の方法を探してみたところ、ObjectScriptから実行することになりますが、
$SYSTEM.Process.TransactionsSuspended()でトランザクションを一時停止すると、その間の更新はバックアップサーバに値は転送されますし、ロールバックしても戻らなくなりました。
例
まず、JRNTEST.Testテーブルに2行追加します。 USER>s r=##class(%SQL.Statement).%ExecDirect(,"insert jrntest.test set p1=1") USER>s r=##class(%SQL.Statement).%ExecDirect(,"insert jrntest.test set p1=1") トランザクションを開始します USER>s r=##class(%SQL.Statement).%ExecDirect(,"start transaction") トランザクションを一時停止します。 TL1:USER>d $SYSTEM.Process.TransactionSuspended(1) ID=1のレコードのカラムP1の値をインクリメントします。 TL1:USER>s r=##class(%SQL.Statement).%ExecDirect(,"update jrntest.test set p1=p1+1 where id=1") トランザクションを再開します TL1:USER>d $SYSTEM.Process.TransactionSuspended(0) ID=2のレコードのカラムP1の値をインクリメントします。 TL1:USER>s r=##class(%SQL.Statement).%ExecDirect(,"update jrntest.test set p1=p1+1 where id=2") 現在値を確認します。 TL1:USER>do ##class(%SQL.Statement).%ExecDirect(,"select * from jrntest.test").%Display() ID p1 1 2 2 2 2 Row(2) Affected ロールバックします TL1:USER>s r=##class(%SQL.Statement).%ExecDirect(,"rollback") 現在値を確認します。 USER>do ##class(%SQL.Statement).%ExecDirect(,"select * from jrntest.test").%Display() ID p1 1 2 2 1 2 Row(s) Affected
よろしくお願いします。
Minamoto さん
ありがとうございます!
トランザクションと関係なくコミットできるのであれば、
1000件アップデートによるテーブルロックも防げそうですし、
期待動作が得られそうです。
頂いた方法で試してみたいと思います。