[Seasar-user:7762] Re: [DBFlute,S2DAO] 楽観的排他制御について

kubo [E-MAIL ADDRESS DELETED]
2007年 5月 23日 (水) 09:33:53 JST


久保です。

> <1>
> DBFluteにて楽観的排他制御の要否を設定するためには、
> build.propertiesに楽観的排他の対象外とするテーブルを
> 指定する方法があるかと思いますが、同一テーブルに対して
> 更新ごとに楽観的排他制御をする/しないを制御することは
> 可能でしょうか?
> 
> 楽観的排他制御の対象テーブルに対しては、必ずVersionNO
> かTimeStampをEntityに設定して更新しないと、更新日時=nullで
> 例外になるようなので。
> 
> もし何か他に方法があるようでしたらご教授お願い致します。

DBFlute-0.4.4よりBehaviorにupdateNonstrict()というMethodがあります。

こちら、Entityに排他制御Annotation(VersionNoとか)を設定していても
このMethod実行時は排他制御が行われません。
VersionNoに値がSETされていようがいまいが
where句の 「and version_no = 3」という条件が付与されません。
http://dbflute.sandbox.seasar.org/ja/tips-behavior-method_for_use.html

_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
【通常のupdate()】
-- version_noに値をSETしたとき → 排他制御あり更新
update XxxTable set xxx_name = 'nn', version_no = version_no + 1
 where xxx_id = 1 and version_no = 6

-- version_noに値をSETしなかったとき → 絶対0件更新
update XxxTable set xxx_name = 'nn', version_no = version_no + 1
 where xxx_id = 1 and version_no = null

【updateNonstrict()】
-- version_noに値をSETするしない関係なし
--     → where句にVersionNo条件が付与されない
update XxxTable set xxx_name = 'nn', version_no = version_no + 1
 where xxx_id = 1

補足:DBFluteでは更新ではupdateModifiedOnly()を利用するため、
      update文のset句はEntityのSetterが呼び出されたものだけで
      構成されます。(VersinoNo/Timestampは例外)
_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/

「画面では排他制御が必要となるがバッチからは不要」というような要件が
必ずあると思い、このようなMethodを用意しています。

updateNonstrict()が無いと、排他制御が不要な場合も更新前に一旦Select
してVersionNoを取得しなければ更新ができません。
そのため、バッチなどのシビアにPerformanceが求められる処理の場合に
つらくなります。updateNonstrict()は一旦Select無しでそのまま更新可能です。

updateNonstrict() → 制限無し(Nonstrict)で更新(upadte)するMethod

こちらで要件満たせますでしょうか?



> <2>
> また、楽観的排他時に処理を続行させたい(メソッド内でcatch)が
> トランザクションはrollbackさせたい、といった場合は
> 何か方法はありますでしょうか?
> transactionAspectCustomizerを該当メソッドに掛けています
> ので例外をthrowしないと通常rollbackしません。
> 該当メソッドではthrowして親クラスでcatchするしかないでしょうか?

こちらは少し確認をさせて下さい。

例えば「Aaaテーブルを更新する処理」と「Bbbテーブルを更新する処理」が
あったとして、あるClassのMethod「aruMethod()」にTransactionが
掛かっているとします。

public void aruMethod() {
    // 1. 「Aaaテーブルを更新する処理」
    // 2. 「Bbbテーブルを更新する処理」
}

「1. Aaa更新」で排他制御アリで更新をし、排他例外になった場合に
aruMethod()を抜けずに、その中で例外をcatchして「2. Bbb更新」の処理を
続行したいというようなイメージでよろしいでしょうか?


もし、そうであれば:

A. Transactionは一貫性を保たなければならない単位の処理に対して
   かけるものなので、aruMethod()にTransactionをかけるべきでなく、

public void aruMethod() {
    updateAaaTable()
    updateBbbTable()
}

というようにして、updateAaaTable()/updateBbbTable()それぞれに
Transactionをかけるようにするべきかと思います。

B. aruMethod()のTransactionが一律のものであって外せない場合は、
   「1. Aaa更新」だけ別Transactionにするとかも考えられます。


もう少し具体的な状況がわかれば別の良い方法があるかもしれません。
とりあえずDBFluteのBehaviorでは、
Method名の最後に「Tx」を付けるとそのMethodは requiredTx になります。
Method名の最後に「NewTx」を付けるとそのMethodは requiresNewTx になります。
これを利用して何かしら工夫できるかもしれません。







Seasar-user メーリングリストの案内