使用 Slick 3.0 在同一事务中进行多次插入

Posted

技术标签:

【中文标题】使用 Slick 3.0 在同一事务中进行多次插入【英文标题】:Multiple inserts in same transaction with Slick 3.0 【发布时间】:2015-07-07 10:31:01 【问题描述】:

我正在使用 slick 2.1.0 将我的 Play Framework 应用程序升级到 play-slick 1.0.0(包括 slick 3.0.0)。

我在理解如何处理交易时遇到了一些问题。

假设我有以下代码:

db.withTransaction  implicit session =>
    for (id <- ids) yield someTable.insert(SomeObject(id))

如何在 slick 3 中做到这一点?我希望将所有对象插入一个事务中。如果一个对象插入失败,则不应插入任何对象。

【问题讨论】:

【参考方案1】:

根据documentation,您可以在db-action 上使用.transactionally

val a = (for 
  ns <- coffees.filter(_.name.startsWith("ESPRESSO")).map(_.name).result
  _ <- DBIO.seq(ns.map(n => coffees.filter(_.name === n).delete): _*)
 yield ()).transactionally

val f: Future[Unit] = db.run(a)

对于您提供的代码,这会产生以下示例:

val a = (for (id <- ids)
   someTable.insert(SomeObject(id))
 yield ()).transactionally

val f: Future[Unit] = db.run(a)

【讨论】:

那行不通。似乎函数insert 不再存在。我尝试将其替换为+=,但这也不起作用。 玩了一会儿后,我想到了这个:val toInsert = for (id &lt;- ids) yield SomeObject(id)val insertActions = DBIO.seq(someTable ++= toInsert.toSeq).transactionallyval f: Future[Unit] = db.run(insertActions)不确定这是否是最好的方法?【参考方案2】:

我有一个稍微不同的场景,我必须在同一个事务中更新两个表,下面的代码似乎是实现这一点的最优雅的方式:

val c: DBIOAction[(Int, Int), NoStream, Effect.Write with Effect.Write] = for
      i1 <- (tbl1 += record1)
      i2 <- (tbl2 += record2)
     yield 
      (i1,i2)
    
val f = db run c.transactionally

看到这里,突然觉得这有点像scala Future的api,所以肯定有sequence方法,而且确实有:

val actions = Seq((tbl1 += record1), (tbl2 += record2))
val dbActions: DBIOAction[Seq[Int], NoStream, Effect.Write with Effect.Transactional]
    =  DBIOAction.sequence(actions).transactionally
val f = db run dbActions

在原始用例中,您可以简单地用您的理解构建动作

【讨论】:

以上是关于使用 Slick 3.0 在同一事务中进行多次插入的主要内容,如果未能解决你的问题,请参考以下文章

Slick 3.0 批量插入或更新(更新插入)

批量插入时 Slick 3.0 中的数据库异常

Slick 3.0插入然后获得自动增量值

jpql sql在同一个事务中

mysql 不同事务隔离级别

在 Slick 3 中以事务方式使用