なんとなくわかってきた

以前のエントリトランザクションのことを書いたけど、さらに、わかってきたので、再びエントリ。
でも多分に推測。

まず、Grails は、基本的に、AutoCommit モードで動作している。
でも、ちゃんと、ロールバックの動きはしてくれる。
どういう仕組みなのだろうか。

そこで出てくるのが、(おそらく)GORMか、Hibernate
Grails は、GORM 経由でデータベースへの書込などを行っているけど、それは、つまり、hibernate を使っていると言うこと。このどちらかが、なんらかの処理をしてくれている。

データベースへの書込が指示された際、すぐさまデータベースへの書込は行われず、メモリ上に蓄積されていく。
コントローラーの処理が終わると、その時点で、データベースへの書込が行われる。
GrailsRuntimeException が発生すると、GORM(Hibernate)が、メモリ上の更新処理をデータベースへ書き込まないわけだ。
なんのことはない。ロールバックしているのではなく、そもそも、データベースへ書き込んでいないのだ。

じゃあ、これで問題ないのかというと、そんなことはない。
GORM(Hibernate)は、大量の更新処理をかけると、なぜか、(やりかたがわるいのか)データの取りこぼしが発生してしまう。
そういうときは、save(flush:true)としてやると、取りこぼしは発生しない。
flush:true とは、そのコマンド(saveなど)が処理されたときに、メモリに蓄積するのではなく、その時点でデータベースへの書込を行ってくれるもののようだ。

となると、先の GrailsRuntimeException が発生した時にどうなるのかというと、当然、ロールバックしてくれない。

やっぱり、トランザクション処理をしてやる必要がある。方法は簡単。

[domainClass].withTransaction{status->
 try{
  ...
 }
 catch(e){
  status.setRollbackOnly()
 }
}

というクロージャー?内でデータベースを処理するロジックを書く。
ここで、[domainInstance]は、実際のドメインを指定する。推測では、GORM の domain は、すべて、Hibernate で言うところの session を管理するクラスを継承しているっぽいので、どんな domain でも、この withTransaction は利用できる。
ロールバックは、このクロージャ内で、status.setRollbackOnly() とすれば、ロールバックしてくれる。

データベース的には、この withTransaction があると、AutoCommit モードが off に設定されるて、処理が終わると、再び、AutoCommit モードが on になるようだ。

これだけわかれば、データベース処理は、なんとか問題にならないようなものを作っていけるかな?