楽観的ロックをためす

GORMのドメインはほっといてもversion属性が付いて,save(flush:true)で楽観的ロックをやってくれる。
http://grails.org/doc/1.0.x/guide/5.%20Object%20Relational%20Mapping%20(GORM).html#5.3.5%20Pessimistic%20and%20Optimistic%20Locking


実際に試してみたらそのスコープがとても狭くて,ちょっとあたしが思っている楽観的ロックと違っていた。どう違ってたか説明するけど,丁寧に説明するのがシンドイのと,とりあえず自分の備忘録になりゃいいや程度の思い入れなんで,そこらへんは行間読んでくれ。
#そうそうGrailsのバージョンは,1.0.4ね。


まずは「あたしが思う楽観的ロック」。まーなんだ,hiddenなりHttpSessionなりに参照時(edit)のversion番号控えておいて,更新時(update)にDB中の該当レコードと値を比較するってアレ。画面をまたぐので,ちょっとスコープが広いね。


それに対して,Grails(GORM)での楽観的ロックはこうだった。←この言い方は,ちょっと誤解がある。「Grailsのstatic scaffoldが生成したコントローラのupdateを元にしたらこうだった」ってのが正しい。要するに,domain.save()をdomain.save(flush:true)にしただけ。


見ての通りスコープがものすごく狭い。トランザクション配下で実行したら,わざわざやらんでも良いんじゃないかってくらい狭い(分離レベルにもよるけど)。
「scaffoldの実装そのまま使うからダメなんじゃね?」って指摘もあるけど,あながちそうだとは言えない。なぜなら,ドメインのversion属性は読み込み専用なのだ(Grails徹底入門 p.482参照)。だから,

persion.version = params.version

とかって出来ない。:-(


「だったら,HttpSessionにドメイン詰めといたら?」って方法もあるけど,あんまりHttpSessionにモノ詰め込むのは好きじゃない。スコープがセッションで良いのかどうかって議論もあるし,GORMの実装がHibernateなんで,attachだのdettachだのを意識するのも,なんかイヤだった。で,なんかやりようないかなぁと思って,たどり着いたのがコレ。


簡単に解説しよう。

  • ドメインクラスに非永続な lock_version 属性を作る。
  • version属性にカスタムバリデータ設定して「lock_versionに値が設定されてたら,versionと同じ値じゃないとダメ」とする。
  • 更新処理を呼び出すGSPのフォームに,version属性の値をlock_versionとして設定する。

これで楽観的ロックがバリデータのタイミングで引っかかるようになる。


まあまあ満足してるが,lock_versionの一連のコードをおまじないとして該当するドメインに書かなきゃいけないってのが,ちょっと気に入らない。ああ,なるほど。そうゆう想いがプラグインを作ってみる動機になるのだなと納得してみるも,それはまた別のお話(にしたい)。
できるかどうかわからんけど,

class Person {
  def static optimisticLock = true
}

てな具合で有効になったらステキだ。:-)


ps.
GORMにデフォで楽観的ロックがあるってんで勝手に期待してたけど,今日びの楽観的ロックってこんなもんなんだ,とも思った。別に否定的な意味はない。むしろ,放っておいても更新が競合するような事って,そんな無いだろうし,仮にあったとしても後勝ちで案外許されるんじゃないかなーって妄想しただけ。いちいち大げさな仕掛けを考えるのは,SI畑の悪いクセだね。あははー。:-D
当然,更新が競合するケースもあるから,そんときゃちゃんと更新ロックかけりゃいい。


(追記) HttpSessionに詰めるのはアレだけど,WebFlowのflowやconversationに詰めるのはアリかもしんない。つうわけで後で試す。