在Slick事务中处理Akka流

在Slick事务中处理Akka流,akka,slick,akka-stream,slick-3.0,Akka,Slick,Akka Stream,Slick 3.0,软件版本: Akka 2.4.4 滑头3.1.0 我想在光滑的事务中处理来自Akka流的元素。 下面是一些简化的代码来说明一种可能的方法: def insert(d: AnimalFields): DBIO[Long] = animals returning animals.map(_.id) += d val source: Source[AnimalFields, _] val sourceAsTraversable = ??? db.run((for { ids <-

软件版本:

  • Akka 2.4.4
  • 滑头3.1.0
我想在光滑的事务中处理来自Akka流的元素。 下面是一些简化的代码来说明一种可能的方法:

def insert(d: AnimalFields): DBIO[Long] =
  animals returning animals.map(_.id) += d

val source: Source[AnimalFields, _]
val sourceAsTraversable = ???

db.run((for {
  ids <- DBIO.sequence(sourceAsTraversable.map(insert))
} yield { ids }).transactionally)
现在我可以将可遍历队列传递给
DBIO.sequence()
。但是,这违背了流式处理的目的


我发现的另一种方法是:

def toDbioAction[T](queue: SinkQueue[DBIOAction[S, NoStream, Effect.All]]):
        DBIOAction[Queue[T], NoStream, Effect.All] =
  DBIO.from(queue.pull() map { tOption =>
    tOption match {
      case Some(action) =>
          action.flatMap(t => toDbioAction(queue).map(_ :+ t))
      case None => DBIO.successful(Queue())
    }
  }).flatMap(r => r)
使用此方法,可以在不阻塞的情况下生成DBIOActions序列:

toDbioAction(source.runWith(Sink.queue()))


有没有更好/更惯用的方法来达到预期的效果?

以下是我对
sourceAsTraversable
的实现:

import scala.collection.JavaConverters._
def sourceAsTraversable[A](source: Source[A, _])(implicit mat: Materializer): Traversable[A] =
    source.runWith(StreamConverters.asJavaStream()).iterator().asScala.toIterable

TraversableQueue
的问题是
forEach
必须完全处理流-它不支持“break”概念,因此像“drop”/“take”等方法仍然必须处理整个源代码。从错误处理和快速失败的角度来看,这可能很重要。

我认为这是一个很好的解决方案。您需要在最后阻塞,以便在单个事务中运行;而且,在调用
db.run()
之前,Slick实际上不会向数据库发送任何内容。
import scala.collection.JavaConverters._
def sourceAsTraversable[A](source: Source[A, _])(implicit mat: Materializer): Traversable[A] =
    source.runWith(StreamConverters.asJavaStream()).iterator().asScala.toIterable