Develop with pleasure!

福岡でCloudとかBlockchainとか。

SquerylのSessionとTransaction

Squeryl使う際のDBとのセッションとトランザクションの管理についてよく分かってなかったので、Sessions and Transactions - Squeryl - A Scala ORM for SQL Databasesをざっと意訳。

org.squeryl.SessionFactoryの初期化

SessionFactory.concreteFactoryはSquerylがトランザクションを実行する前に初期化されている必要がある。

import org.squeryl.SessionFactory

  Class.forName("org.postgresql.Driver");

  SessionFactory.concreteFactory = Some(()=>
  Session.create(
      java.sql.DriverManager.getConnection("..."),
      new PostgreSqlAdapter))

SessionFactory.concreteFactoryの初期化後にtransactionとinTransactionブロックが有効になる。

 import org.squeryl.PrimitiveTypeMode._
 
//Squeryl database interaction must occur in a transaction block : 
transaction {
   books.insert(new Author(1, "Michel","Folco"))	   	   
   val a = from(authors)(a=> where(a.lastName === "Folco") select(a))
}

inTransaction {
   authors.where(a=> a.lastName === "Pouchkine")
   
   //when in a transaction, the current session can be obtained with :
   val s = Session.currentSession
}

transaction関数は、そのブロックに記述されている処理の間、sessionを現在のスレッドにバインドする。そのためブロック内から(直接的に及び間接的に)呼び出される全てのメソッドはトランザクションのコンテキストになる。

transactionとinTransactionの違い

外部のトランザクション管理の仕組みを使う場合

フレームワーク等で提供されるトランザクション管理の機能を利用する場合、Squerylはjava.sql.Connectionを使用する必要がある。(このコネクションはスレッドローカルに保持されている。)外部トランザクション管理を行う場合は事前に↓のようにSessionFactorye.externalTransactionManagementAdapterで初期化する必要がある。

SessionFactorye.externalTransactionManagementAdapter = Some(
  () => new Session(
     ...obtain the current session here ...
     new OracleAdapter
  )
) 

トランザクションを自前で管理する場合

using関数にorg.squeryl.Sessionを渡して管理する。

using(squerylSession) {
  // your Squeryl code here...
} 

※ usingを使う場合は必ずコネクションのクローズ処理を書く必要がある。
※ usingブロック内でinTransactionブロックを呼び出しても効果は無い。inTransactionがあるとトランザクションを実行したように振る舞う。

意訳Done。

普通に使用する分には特に問題ないんだけど、Squeryl使ったコードのテスト書く際に、実際のテスト実施後にはコミットではなくデータのロールバックしたいとかいうのは無理くさい?Rubyだとbmabey/database_cleaner · GitHubとかあるから便利なんだけどなー。