我最近从Slick-2切换到Slick-3。使用slick-3,一切都运行得很好。然而,当涉及到交易时,我遇到了一些问题。我见过使用transactionally和withPinnedSession处理事务的不同问题和示例代码。但我的情况略有不同。transcationally和withPinnedSession都可以在Query上应用。但我想要做的是将相同的会话传递给另一个方法,该方法将执行一些操作,并希望在同一事务中包装多个方法。
我有下面的slick-2代码,我不确定如何使用Slick-3实现这一点。
def insertWithTransaction(row: TTable#TableElementType)(implicit session: Session) = {
val entity = (query returning query.map(obj => obj) += row).asInstanceOf[TEntity]
// do some operations after insert
//eg: invoke another method for sending the notification
entity
}
override def insert(row: TTable#TableElementType) = {
db.withSession {
implicit session => {
insertWithTransaction(row)
}
}
}现在,如果有人对拥有事务不感兴趣,他们可以只调用insert()方法。如果我们需要做一些事务,可以通过在db.withTransaction块中使用insertWithTransaction()来完成。
例如:
db.withTransaction { implicit session =>
insertWithTransaction(row1)
insertWithTransaction(row2)
//check some condition, invoke session.rollback if something goes wrong
}但使用slick-3时,事务性只能应用于查询。这意味着,在我们需要在插入后集中做一些逻辑的地方,它都是可能的。如果使用事务,每个开发人员都需要手动显式地处理这些场景。我认为这可能会导致错误。我试图在insert操作中抽象出整个逻辑,这样实现者只需要关心事务的成功/失败
在slick-3中,有没有其他方法可以将相同的会话传递给多个方法,以便在单个db会话中完成所有操作。
发布于 2015-06-17 00:55:03
您遗漏了一些东西:.transactionally不适用于Query,而适用于DBIOAction。然后,可以使用一元组合将多个查询组合成一个DBIOAction。
以下是文档中的一个示例:
val action = (for {
ns <- coffees.filter(_.name.startsWith("ESPRESSO")).map(_.name).result
_ <- DBIO.seq(ns.map(n => coffees.filter(_.name === n).delete): _*)
} yield ()).transactionallyaction由一个select查询和与第一个查询返回的行数相同的delete查询组成。所有这些都会创建在事务中执行的DBIOAction。
然后,要对数据库运行操作,您必须调用db.run,因此,如下所示:
val f: Future[Unit] = db.run(action)现在,回到您的示例,假设您想要在插入之后应用update查询,您可以这样创建一个操作
val action = (for {
entity <- (query returning query.map(obj => obj) += row)
_ <- query.map(_.foo).update(newFoo)
} yield entity).transactionally希望能有所帮助。
https://stackoverflow.com/questions/30371450
复制相似问题