Screaming Loud

日々是精進

Slickで複数のDBスキーマのトランザクションを行う

Slickでのトランザクション

Slickでトランザクション処理を行うとすれば、公式のドキュメントに載っているように以下の様な処理を書けば良いと思います。

db.withTransaction{
  implicit session =>
  // your queries go here
}

一般的にDB間をまたいでトランザクションを行う場合、フレームワーク側で吸収することが多いので、あまりORマッパーでそういう機能を提供することは少ないのではないかと思います。

しかし、spray-slickの組み合わせでシステムを組むと、sprayにも複数DB間のトランザクションを組む実装がありません。

そこで、複数DB間のトランザクションを行えるものを作ってみました。

分散トランザクション

複数のDBのトランザクションを実現するには、auto-commitをoffにし、全てのクエリが投げ終わったあとでauto-commitをonにすることで実現できます。

以下がわかりやすいページになります。
分散トランザクションに挑戦しよう!

実際のコード

今回その複数トランザクションの部分をメソッド化したものが以下のコードです。

解説

example.scalaにもあるように、
multiTransactionでは引数を2つ取り、

  1. 一つ目の引数では、トランザクション内で利用するDatabaseResourceを受け取ります。ここに関して、Seqで渡すようにしてあります。
  2. 2つ目の引数は、関数を受け取るようにしています。この関数の引数に、DatabaseResourceをSessionに変換して渡すことで、関数内ではトランザクション処理を気にすること無く、クエリを実行することができます。

実際のINSERT処理部分では、sessionを渡しています。
通常、Slickではimplicitでsessionを渡すことが多いので、sessionを書く習慣はないと思いますが、
各クエリがどのDBに対してクエリを投げるのかを指定するために、sessionを引数に書いています。

また、multiTransaction内で、何かExceptionが発生した場合、引数で受け取っている全てのDatabaseResourceをロールバックします。


It can create transaction over multi DB schema by Slick

ここ、こうしたほうがいいよ的なのがあれば、コメント送ってもらえると嬉しいです

所感

sprayを使いはじめる人は、ココらへん苦労しそうなので、テンプレートのプロジェクトを作りたいなと思いました。
s4をforkしてつくろうかなー。