如何在Slick中使用交易

Vee*_*ich 1 scala slick-3.0

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

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))))
        }
  }
Run Code Online (Sandbox Code Playgroud)

我叫它两次

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)
  }
Run Code Online (Sandbox Code Playgroud)

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

如何解决此问题,我不理解,也不在第一个onComplete中插入。只是叫它两次。

谢谢。

Pau*_*ega 5

这是一个常见的错误-转换为Future早期(换句话说,称为db.run(...)早期)。

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

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

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

然后,您需要将返回类型更改为此(更改FutureDBIO):

def insert(newCategory: CategoryExtractor): DBIO[Either[String, CategoryResponse]] = {
...
  }
Run Code Online (Sandbox Code Playgroud)

而且比您这样做:

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))
Run Code Online (Sandbox Code Playgroud)

基本上,事情是:一旦您转换DBIOFuture捆绑交易,您就会失去将动作捆绑为单个交易的能力。所以,你基本上做的一切与使用DBIO的不同变换的(一般的东西:mapflatMapseq等),仅作为最后一步,你火db.run(yourComposedDbio.transactionally)

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

戴夫·古内尔(Dave Gurnell)主持了一个很棒的讲习班,他在以下时间谈论这个话题:01:05:00(链接在这里:https ://vimeo.com/148074461 )