【问题标题】:How to use transaction in slick如何在 slick 中使用事务
【发布时间】:2016-12-19 09:14:32
【问题描述】:

我有这样的插入方法(权重是索引)

implicit def run[A](action: DBIOAction[A, NoStream, _ <: slick.dbio.Effect]): Future[A] = {
    db.run(action)
  }

def insert(newCategory: CategoryExtractor): Future[Either[String, CategoryResponse]] = {
        category.map(_.weight).max.result.flatMap {
          case Some(weight) =>
            val temp = newCategory.copy(weight = weight+1)
            (category += temp).andThen(DBIO.successful(Right(toCategoryExtractor(temp))))
          case None =>
            val temp = newCategory.copy(weight = 1)
            (category += temp).andThen(DBIO.successful(Right(toCategoryExtractor(temp))))
        }
  }

我称它为 2 次​​p>

insert(CategoryExtractor("1", "name", "scala every where", 0, 0, 0, None)) onComplete {
    case Success(data) => println(data)
  }

insert(CategoryExtractor("2", "name", "haskell every where", 0, 0, 0, None)) onComplete {
    case Success(data) => println(data)
  }

它返回异常(唯一索引)。

如何解决这个问题,我不使用理解或插入第一个 onComplete。只需调用 2 次即可。

谢谢。

【问题讨论】:

    标签: scala slick-3.0


    【解决方案1】:

    这是一个常见的错误 - 将 Future 转换为 early(换句话说,将 db.run(...) 调用为 early)。

    您需要做的是删除此方法,因为它(可能有点不直观)弊大于利:

    implicit def run[A](action: DBIOAction[A, NoStream, _ <: slick.dbio.Effect]): Future[A] = {
        db.run(action)
      }
    

    经验法则基本上是您通常希望严格控制您的实际数据库交互(和事务边界),因此我建议不要在该领域使用任何类型的implicits。毕竟它是这个库背后的驱动思想之一 - Slick 试图在应用程序和 db 之间的交互中非常明确(与经典 ORM 相反 - 其中使用访问器可能实际上触发了对 db 的延迟调用或通过 mutator 设置值可能会导致实际的数据库更新)。

    那你需要把返回类型改成这个(把Future改成DBIO):

    def insert(newCategory: CategoryExtractor): DBIO[Either[String, CategoryResponse]] = {
    ...
      }
    

    比你这样做:

    val firstInsert = insert(CategoryExtractor("1", "name", "scala every where", 0, 0, 0, None)) map {
        data => println(data)
    }
    
    val secondInsert = insert(CategoryExtractor("2", "name", "haskell every where", 0, 0, 0, None)) map {
        data => println(data)
    }
    
    db.run(DBIO.seq(firstInsert, secondInsert).transactionally))
    

    基本上事情是:一旦你将DBIO 转换为Future,你就失去了将动作捆绑到单个事务中的能力。所以你基本上可以使用不同的 DBIO 转换来做所有事情(通常的东西:mapflatMapseq 等),并且仅作为您触发 db.run(yourComposedDbio.transactionally) 的最后一步。

    编辑: 以下是我几周前的演示文稿中有关处理交易和DBIO 组合的更多信息。相关幻灯片:http://slides.com/pdolega/slick-101#/85(以及更多)。

    Dave Gurnell 还举办了一个很棒的研讨会,他在 01:05:00 左右谈到了这个问题(链接在这里:https://vimeo.com/148074461

    【讨论】:

    • 那行得通,我有一个新问题。我有 List(dataToUpdate) 并且我想将它们更新到数据库中。我的代码 => db.run((for { ns &lt;- DBIO.sequence(a.map(x =&gt; category.filter(_.id === x.uuid).update(x))) } yield ns).transactionally) 如果列表中的 uuid 在数据库中没有回滚它。我尝试以事务方式使用,但它不会为我回滚
    • 使用 println(data) 作为未来的处理方式并不是执行实际操作的好例子。你应该演示一些不返回单位的东西
    • 嘿@AndrewNorman 总的来说我同意。在这种特殊情况下,我不确定 - 答案试图尽可能地模仿问题的上下文(println 来自问题)。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-05-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多