假设我有一个看起来像这样的模型:
case class User(username: String, dateOfBirth: Timestamp, lastSentGift: Timestamp)
假设我有一个适当的随附Slick模式Users
,如何在事务中对该表执行多个查询,并在两者之间调用scala函数?
我已经看到Slick提供了DBIOAction
和DBIO.seq
来允许在单个事务中组合多个数据库操作,但是我不知道我是否/如何将它们与scala一起使用函数之间调用。
例如,我想做这样的事情,但是将所有事情都放在一个事务中:
def prepareGiftFor(user: User): Timestamp = ???
val usersWithBirthdays = db.run(
Users.filter { user =>
user.dateOfBirth > (now - 1 month) && user.lastSentGift < (now - 1 month)
}
.limit(100)
.forUpdate
)
usersWithBirthdays
.map(user => (user.username, prepareGiftFor(user)))
.map { case (username, lastSentGift) =>
db.run(
Users.withFilter(_.username === username)
.map(row => row.lastSentGift)
.update(lastSentGift)
)
}
答案 0 :(得分:1)
光滑的一般想法是尽可能延迟db.run
通话。首选方式是使用DBIOAction
实例并像使用scala Future
或Option
一样链接它们。
为此,DBIOAction
支持map
和flatMap
方法。 DBIOAction伴随对象还包含辅助方法from
,successful
和failed
。使用它们,您可以从原始值构造DBIOAction
。有关更多信息,请查看slick documentation的有关动作组成的这一部分。
可以通过在DBIOAction
实例上调用transactionally在单个事务中运行所有sql查询。
您的示例可以重写为:
def prepareGiftFor(user: User): Timestamp = ???
def findUsersWithBirthdays(): DBIO[Seq[User]] = {
Users
.filter { user =>
user.dateOfBirth > (now - 1 month) && user.lastSentGift < (now - 1 month)
}
.limit(100)
.forUpdate
}
def updateUsers(users: Seq[User]): Seq[DBIO[Int]] = {
users
.map(user => (user.username, prepareGiftFor(user)))
.map {
Users
.withFilter(_.username === username)
.map(row => row.lastSentGift)
.update(lastSentGift)
}
}
db.run(
(for {
users <- findUsersWithBirthdays()
_ <- DBIO.sequience(updateUsers(users))
} yield ()).transactionaly
)