我最近从 Slick-2 切换到 Slick-3。使用 slick-3 一切正常。但是,我在交易方面遇到了一些问题。
我见过不同的问题和示例代码,其中 transactionally
和 withPinnedSession
用于处理事务。但我的情况略有不同。 transcationally 和 withPinnedSession 都可以应用于 Query
.但是我想要做的是将同一个 session 传递给另一个方法,该方法将执行一些操作并希望在同一个事务中包装多个方法。
我有下面的 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()
方法。如果我们需要做一些交易,可以使用
insertWithTransaction()
来完成。在 db.withTransaction
堵塞。例如:
db.withTransaction { implicit session =>
insertWithTransaction(row1)
insertWithTransaction(row2)
//check some condition, invoke session.rollback if something goes wrong
}
但是使用 slick-3,事务性只能应用于查询。
这意味着,无论我们在哪里需要在插入后集中做一些逻辑,都是可能的。如果使用事务,每个开发人员都需要明确地手动处理这些场景。我相信这可能会导致错误。我试图在插入操作中抽象整个逻辑,以便实现者只需要担心事务成功/失败
有没有其他方法,在 slick-3 中,我可以将同一个 session 传递给多个方法,以便一切都可以在单个 db session 中完成。
最佳答案
你错过了一些东西:.transactionally
不适用于 Query
, 但到 DBIOAction
.
然后,一个 DBIOAction
可以通过使用 monadic 组合由多个查询组成。
这是来自文档的示例:
val action = (for {
ns <- coffees.filter(_.name.startsWith("ESPRESSO")).map(_.name).result
_ <- DBIO.seq(ns.map(n => coffees.filter(_.name === n).delete): _*)
} yield ()).transactionally
action
由 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
希望能帮助到你。
关于scala - 在 Slick 3 中的多种方法之间共享数据库 session ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30371450/