对我而言,最方便的事务管理是对整个http请求使用一个可选事务。这意味着第一个SQL语句应该从池中检索连接,启动事务,并且在请求处理完成后,事务应该被提交(或者在抛出异常时回滚)并且连接应该关闭。当然,如果需要,更细粒度的事务管理必须是可能的。每个请求播放2次交易
Play 2是否支持开箱即用?我可能可以自己实现它,但我正在寻找现成的解决方案。
我看着DB对象,但似乎每次都使用新的连接(和事务)。
我正在使用Scala和Anorm db库,如果它很重要。
对我而言,最方便的事务管理是对整个http请求使用一个可选事务。这意味着第一个SQL语句应该从池中检索连接,启动事务,并且在请求处理完成后,事务应该被提交(或者在抛出异常时回滚)并且连接应该关闭。当然,如果需要,更细粒度的事务管理必须是可能的。每个请求播放2次交易
Play 2是否支持开箱即用?我可能可以自己实现它,但我正在寻找现成的解决方案。
我看着DB对象,但似乎每次都使用新的连接(和事务)。
我正在使用Scala和Anorm db库,如果它很重要。
DB.withTransaction
是你想要的。就像DB.withConnection
一样,它将为连接池提供所有包含的SQL函数的单个连接。既然你想为每个请求使用一个事务,看起来在控制器函数中调用它是最有意义的,并且要求你所有的模型函数都有一个隐含的连接参数。
型号:
object Product {
def checkInventory(id: Long)(implicit c: Connection): Int = SQL(...)
def decrementInventory(id: Long, quantity: Int)(implicit c: Connection): Boolean = SQL(...)
}
object Cart {
def addItem(id: Long, quantity: Int)(implicit c: Connection): Boolean = SQL(...)
}
控制器功能:
def addToCart(id: Long, quantity: Int) = Action {
DB.withTransaction{ implicit connection =>
if(Product.checkInventory(id) >= quantity && Product.decrementInventory(id, quantity)) {
Cart.addItem(id, quantity)
....
} else {
BadRequest
}
}
}
免责声明:这显然不是一个逻辑上的声音购物车交易,并利用数据库事务的只是一个简单的例子。
继Action
组成的例子在documentation,你可以做一个特殊的Transaction
的行动,规定交易,自动每个请求:
object Transaction extends ActionBuilder[Request] {
def invokeBlock[A](request: Request[A], block: (Request[A]) => Future[Result]) = {
DB.withTransaction{implicit connection => block(request)}
}
}
并使用它,就像Action
:
def addToCart(id: Long, quantity: Int) = Transaction {
Product.checkInventory(id)
...
}
陷阱:以这种方式为每个请求提供事务处理非常方便,尤其是当您的大多数控制勒勒函数应该表示原子动作。但是,此方法将不会从交易中释放Connection
,直到Result
已返回给用户。这意味着,如果您要返回一个需要很长时间才能为客户端提供服务/呈现的大型数据集,那么您将持续保持连接的时间长于您真正需要的时间。
让所有的DB.withConnection都行动起来好吗?你可以用蛋糕模式或DaoManager之类的东西来做更好的分层设计吗? –
您需要指定至少使用哪种数据库方法以及使用哪种语言(Java/Scala) – biesior
我正在使用Scala和Anorm db库。 – vbezhenar
我期望更通用的解决方案,而不需要更改控制器,但可能它不存在。我会检查你的回应。 – vbezhenar