Scala控制Hibernate事务
之前用了Scala Slick ORM框架来操作数据库,感觉有点不太好用,想想还是换回Hibernate吧。这样别人用起来会方便一点。之前Slick我也没去看它的事务是怎么处理的,既然现在换回了Hibernate,当然得考虑一下。项目中没打算去集成Spring之类的框架,那么事务的处理就得自己处理了。
Websocket的通信是服务器与客户端保持一个长连接,每次发消息过来不是一个单独请求,当然也不会产生一个单独线程。那么我就考虑通过AOP方式对方法进行拦截,用Scala的话可以通过混入式编程的方式来实现AOP。但是拦截的方法是trait中固定的,这里就很不方便了。所以我这里采用了将方法作为参数传递给基类的方法,在基类来做session的创建销毁,transaction的开启提交。
实现DAO
class MemberDao (session: Session){ def getFirst(q: Query): Any = if (q.list().size() > 0) q.list().get(0) else null 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] } }
定义Hibernate SessionFactory基类
定义一个处理Hibernate SessionFactory的基类,这里创建Session用了openSession
方法
,并没有用getCurrentSession
方法。
因为我们是对service的每个方法进行拦截,并不和当前线程绑定。
所以如果前一个方法提交了事务,那么getCurrentSession
产生的Session就会被自动Close掉了。
接着调用获取的Session就无法打开。
object SessionFactoryHelper { lazy val sessionFactory = new AnnotationConfiguration().configure().buildSessionFactory() var _session: Session = _ def getSession = if (_session != null && _session.isOpen()) _session else sessionFactory.openSession() }
定义BaseSevice
定义一个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 } }
具体的业务Service
具体的业务Service,这里会将当前session穿给每一个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) } }
测试
测试代码:
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