【问题标题】:Scala transactional block with for comprehension带有理解的Scala事务块
【发布时间】:2012-06-05 22:18:45
【问题描述】:

被我创建的 DAO 层卡住了;在单一情况下工作得很好,但是当需要在事务块中保留几个 bean 实例时,我发现我已经把自己编码到了一个角落。为什么?查看下面的 DAO 创建方法:

def create(e: Entity): Option[Int] =
  db.handle withSession { implicit ss: Session=>
    catching( mapper.insert(e) ) option match {
      case Some(success) => Some(Query(sequenceID))
      case None => None
    }
  }

在会话块中发生的查询设置为自动提交,因此我无法将多个持久性操作包装在事务块中。例如,这是一个处理新成员订阅的简化理解

val result = for{
  u <- user.dao.create(ubean)
  m <- member.dao.create(mbean)
  o <- order.dao.create(obean)
} yield (u,m,o)
result match {
  case Some((a,b,c)) => // all good
  case _ => // failed, need to rollback here
}

我可以手动执行查询,但速度很快就很难看

db.handle withSession { implicit ss: Session=>
  ss.withTransaction {
    val result = for{
      u <- safe( UserMapper.insert(ubean) )
      ...
    }
    def safe(q: Query[_]) = 
      catching( q ) option match {
        case Some(success) => Some(Query(sequenceID))
        case None => None
      }
  }
}

因为我最终会重复错误处理,因此必须在整个应用程序中提供数据库、会话等,而不是封装在 DAO 层中

这里有人对如何解决这个问题有一些明智的建议吗?我真的很喜欢 for comprehension 的简洁性,Scala 摇滚 ;-),想法赞赏!

【问题讨论】:

    标签: scala transactions persistence dao


    【解决方案1】:

    好的,除非有人有更好的主意,否则我将采用以下方法:

    由于 DAO 到实体是一对一的关系,并且 ScalaQuery 自动提交在会话块中执行的查询,因此通过我的 DAO 实现不可能在单独的实体上执行多个插入。

    解决方法是创建一个不绑定到特定实体的 GenericDAO,它提供事务查询功能,并将错误处理提取到父 trait 中

        def createMember(...): Boolean = {
          db.handle withSession { implicit ss: Session=>
            ss.withTransaction {
              val result = for{
                u <- safeInsert( UserMapper.insert(ubean) )(ss)
                ...
              }
              ...
    

    在控制器层,实现变为dao.createMember(...),这非常好,imo,事务性插入使用安全的理解,很酷的东西。

    【讨论】:

      猜你喜欢
      • 2013-10-01
      • 2021-08-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-11-21
      • 1970-01-01
      • 1970-01-01
      • 2013-07-10
      相关资源
      最近更新 更多