Scala+Hibernateトランザクションの1つ

3314 ワード

ScalaでHibernateトランザクションを使用する処理
現在、Scalaで書かれたプロジェクトOschatの中で、以前はScala Slick ORMフレームワークでデータベースを操作していましたが、ちょっと使いにくい感じがします.やはりHibernateに交換しましょう.これで他の人が使いやすいです.以前Slickもその事務がどのように処理されているのか見に行かなかったので、今Hibernateに戻った以上、もちろん考えなければなりません.プロジェクトでSpringなどのフレームワークを統合するつもりはないので、トランザクションの処理は自分で処理しなければなりません.
Websocketの通信はサーバがクライアントと長い接続を維持し、メッセージを送信するたびに個別の要求ではなく、もちろん個別のスレッドも生成されません.そこで私はAOP方式でメソッドをブロックすることを考え,Scalaであれば混入プログラミング方式でAOPを実現できる.しかしブロックの仕方はtraitで固定されており、ここでは不便です.そこで私はここでメソッドをパラメータとしてベースクラスに渡す方法を採用し,ベースクラスでsessionの作成破棄,transactionのオープンコミットを行う.
具体的な実装
1.Hibernate SessionFactoryを処理するベースクラスを定義します.ここでSessionを作成するにはopenSessionメソッドが使用され、getCurrentSessionメソッドは使用されません.サービスの各メソッドをブロックするため、現在のスレッドにバインドされません.したがって、前のメソッドがトランザクションをコミットすると、getCurrentSessionによって生成されたSessionは自動的にCloseされます.取得したセッションを呼び出すと開けません
object SessionFactoryHelper {
  
  lazy val  sessionFactory = new AnnotationConfiguration().configure().buildSessionFactory()
  var _session:Session = _
  def getSession = if(_session!=null && _session.isOpen()) _session else sessionFactory.openSession()
  
}

2.パラメータとしてメソッドを受け入れるメソッドを定義し、そのメソッドの前後でトランザクションを処理するBaseServiceを定義します.warpSessionメソッドでは,f,すなわちサブクラスで通過するメソッドを呼び出した.その後、その前後でトランザクションが処理されます.
abstract class BaseService {
  def getSession = SessionFactoryHelper.getSession
  def withTransaction[T](f: => T): T = warpSession(f)

  private def warpSession[T](f: => T): T = {
    if(getSession.getTransaction().wasCommitted())
    	getSession.getTransaction().begin()
    println("Transaction begin")
    val t = f
    if(getSession.getTransaction().isActive())
    	getSession.getTransaction().commit()
    getSession.close()
    println("Transaction commit")
    t
  }
}

3、具体的な業務サービスは、現在のセッションを各daoに提供し、各daoが実行された後、事務を提出します.ここで我々の各メソッドは,BaseServiceのwithTransactionメソッドを呼び出し,そのメソッド体をベースクラスに渡す.
class MemberService extends BaseService{

  private val dao = new MemberDao(getSession)
  
  def getMemberbyUsername(username:String):Member= withTransaction{
    dao.getMemberbyUsername(username)
  }
  
  def getMemberbyUid(uid:String):Member =withTransaction{
    dao.getMemberbyUid(uid)
  }
}

4、Daoのコード、ここで私達は1つのBaseDaoをプラスして、いくつか共通の方法を処理します
class MemberDao (session:Session){
  
  def getMemberbyUsername(username:String):Member={
    val sql = "from me.feng.domain.Member t where t.username=?"
    val q = session.createQuery(sql).setParameter(0, username)
    getFirst(q).asInstanceOf[Member]
  }
  
  def getMemberbyUid(uid:String):Member = {
    println(session.toString)
    session.get(classOf[Member],uid).asInstanceOf[Member]
  }
  
  def getFirst(q:Query):Any ={
    if(q.list().size()>0) q.list().get(0) else null
  }
  
}

5、テストコードと結果
object DaoTest {
  def main(args: Array[String]) {
	  val d = new MemberService()
	  val m =d.getMemberbyUsername("254662")
	  val m2 =d.getMemberbyUid("254662")
	  println(m.nickname)
	  println(m2.createTime)
  }
}
Transaction begin
Dao getMemberbyUsername
Transaction commit
Transaction begin
Dao getMemberbyUid
Transaction commit
ForEleven
2013-08-26 16:57:22.0

このような方法はまあまあ簡単ですが、サービス方法を書くとき=後にwithTransactionが1つ増えただけです