Database transactions in Play framework scala applications (anorm)

后端 未结 2 2045
耶瑟儿~
耶瑟儿~ 2021-01-22 17:04

I am developing an application using Play framework and scala. I am using anorm for data-access layer. And I\'ve got a problem I could not solve.

Brief:

相关标签:
2条回答
  • 2021-01-22 17:42

    What about

    class Dao {
      def foo(id: Long)(implicit connection: Connection) = {
        SQL("select * from foo where id={id}").on('id->id).as(...)
      }
    }
    
    class Service{
      def withConnection = {
        DB.withConnection {implicit connection =>
          Dao.foo(1)
          Dao.foo(2)
        }
      }
    
      def withTransaction = {
        DB.withTransaction {implicit connection =>
          Dao.foo(1)
          Dao.foo(2)
      }
    }
    
    0 讨论(0)
  • 2021-01-22 17:54

    The solution I've seen used elsewhere (principally in Squeryl), is roughly the following:

    import java.sql.Connection
    object Helper {
      private val conn: ThreadLocal[Connection] = new ThreadLocal
    
      def inTransaction[X](f: Connection => X) = {
        conn.get() match {
          case null =>
            DB.withConnection { newConn =>
              conn.set(newConn)
              try f(newConn)
              finally conn.set(null)
            }
          case c => f(c)
        }
      }
    }
    

    This way, the inTransaction method is re-entrant, so there's no harm in calling it redundantly inside dao.select.

    If you prefer, you can expose conn via a public method, and change the signature of f to => X - you lose some compile-time safety, but the API is a little cleaner.

    One pitfall with this approach is that connections are tied to threads, which may cause problems if you're using futures or actors, and a process can resume on a different thread (this is a tricky area anyway, but one you should be aware of).

    You might want to look into Squeryl too - it may already do what you need.

    0 讨论(0)
提交回复
热议问题