Play 2.4 中的 Slick 3.0 交易
Slick 3.0 transactions in Play 2.4
我有一个控制器,它对数据库模型 类 进行各种调用,在 PostgreSQL 数据库上执行各种操作。我想在单个事务中执行所有这些操作。在 Play 2.3 中,我能够将代码包装在 DB.withTransaction { ... }
中以使其在单个事务中执行所有操作。
对于 Play 2.4 和 Slick 3.0,Slick 似乎处理连接管理,DB.withTransaction
似乎不再是处理此问题的正确方法(它抛出 IllegalArgumentException
消息 "Could not find database for default"反正)。从控制器内部对事务内的 Slick 操作进行分组的正确方法是什么?
你的问题的解决方案是DBIO composition。
首先,你所有的原子操作都应该由一个DBIOAction
实现(一个DBIOAction
代表一个将在数据库上执行的操作)。
接下来,您可以将所有 DBIOAction 组合在一起,使用 andThen
、flatMap
,或使用 for comprehension
(参见 DBIOAction api)
当您拥有组合的 DBIO 时,您可以调用 .transactionally
使 DBIOAction 在 db 上执行时具有事务性。
样本:
def updateUsername(id: Long, username: String) = Schemas.users.filter(_.id === id).map(_.username).update(username)
def updateUserAddress(id: Long, address: String) = Schemas.addresses.filter(_.id === id).map(_.address).update(address)
def getUser(id: Long) = Schemas.users.filter(_.id === id).head
val operations = for {
_ <- updateUserName(1, "foo")
_ <- updateUserAddress(1, "bar")
user <- getUser(1)
} yield user
db.run(operations.transactionally)
获取db
对象的方法在Play文档中有说明。
我有一个控制器,它对数据库模型 类 进行各种调用,在 PostgreSQL 数据库上执行各种操作。我想在单个事务中执行所有这些操作。在 Play 2.3 中,我能够将代码包装在 DB.withTransaction { ... }
中以使其在单个事务中执行所有操作。
对于 Play 2.4 和 Slick 3.0,Slick 似乎处理连接管理,DB.withTransaction
似乎不再是处理此问题的正确方法(它抛出 IllegalArgumentException
消息 "Could not find database for default"反正)。从控制器内部对事务内的 Slick 操作进行分组的正确方法是什么?
你的问题的解决方案是DBIO composition。
首先,你所有的原子操作都应该由一个DBIOAction
实现(一个DBIOAction
代表一个将在数据库上执行的操作)。
接下来,您可以将所有 DBIOAction 组合在一起,使用 andThen
、flatMap
,或使用 for comprehension
(参见 DBIOAction api)
当您拥有组合的 DBIO 时,您可以调用 .transactionally
使 DBIOAction 在 db 上执行时具有事务性。
样本:
def updateUsername(id: Long, username: String) = Schemas.users.filter(_.id === id).map(_.username).update(username)
def updateUserAddress(id: Long, address: String) = Schemas.addresses.filter(_.id === id).map(_.address).update(address)
def getUser(id: Long) = Schemas.users.filter(_.id === id).head
val operations = for {
_ <- updateUserName(1, "foo")
_ <- updateUserAddress(1, "bar")
user <- getUser(1)
} yield user
db.run(operations.transactionally)
获取db
对象的方法在Play文档中有说明。