Scala 使用Akka Streams 2.4.2和Slick 3.0阅读博士后

Scala 使用Akka Streams 2.4.2和Slick 3.0阅读博士后,scala,akka-stream,slick-3.0,Scala,Akka Stream,Slick 3.0,尝试新铸造的阿克卡溪流。它似乎在工作,除了一件小事——没有输出 我有以下表格定义: case class my_stream(id: Int, value: String) class Streams(tag: Tag) extends Table[my_stream](tag, "my_stream") { def id = column[Int]("id") def value = column[String]("value") def * = (id, value) <

尝试新铸造的阿克卡溪流。它似乎在工作,除了一件小事——没有输出

我有以下表格定义:

case class my_stream(id: Int, value: String)

class Streams(tag: Tag) extends Table[my_stream](tag, "my_stream") {
  def id = column[Int]("id")
  def value = column[String]("value")
  def * = (id, value) <> (my_stream.tupled, my_stream.unapply)
}
我已经通过配置调试日志来验证查询是否正在运行。然而,我得到的只是:

08:59:24.099 [main] INFO  com.zaxxer.hikari.HikariDataSource - pg-postgres - is starting.
08:59:24.428 [main] INFO  com.zaxxer.hikari.pool.HikariPool - pg-postgres - is closing down.

最后使用了@ViktorKlang answer,并用
wait.result
结束了运行。我还找到了一个替代答案,该答案演示了如何使用反应流发布者和订阅者界面:

stream
方法返回一个
DatabasePublisher[T]
Source。fromPublisher
返回一个
Source[T,NotUsed]
。这意味着您必须连接订户,而不是使用
runForEach
——根据
说明,NotUsed
单元的替代品。这意味着不会将任何内容传递到
接收器

由于Slick实现的是反应流接口,而不是Akka流接口,因此您需要使用来自Publisher的
和来自Subscriber的
集成点。这意味着您需要实现
org.reactivestreams.Subscriber[T]
接口

下面是一个快速而肮脏的
Subscriber[T]
实现,它只调用
println

class MyStreamWriter extends org.reactivestreams.Subscriber[my_stream] {
  private var sub : Option[Subscription] = None;

  override def onNext(t: my_stream): Unit = {
    println(t.value)
    if(sub.nonEmpty) sub.head.request(1)
  }

  override def onError(throwable: Throwable): Unit = {
    println(throwable.getMessage)
  }

  override def onSubscribe(subscription: Subscription): Unit = {
    sub = Some(subscription)
    sub.head.request(1)
  }

  override def onComplete(): Unit = {
    println("ALL DONE!")
  }
}
您需要确保在
onSubscribe
中调用
Subscription.request(Long)
方法,然后在
onNext
中调用以请求数据,否则将不发送任何内容,否则将无法获得完整的结果集

下面是您如何使用它:

def main(args: Array[String]) : Unit = {
  implicit val system = ActorSystem("Subscriber")
  implicit val materializer = ActorMaterializer()

  val strm = TableQuery[Streams]
  val db = Database.forConfig("pg-postgres")

  try{
    val src = Source.fromPublisher(db.stream(strm.result))
    val flow = src.to(Sink.fromSubscriber(new MyStreamWriter()))
    flow.run()
  } finally {
    system.shutdown
    db.close
  }
}

我仍在努力解决这个问题,所以我欢迎任何反馈。谢谢

原因是Akka流是异步的,
runForeach
返回一个未来,该未来将在流完成后完成,但是,这种未来并没有得到处理,因此,
系统.shutdown
db.close
会立即执行,而不是在流完成后执行。

为了帮助任何人在MySQL中搜索同一问题,请考虑到您应该“手动”启用驱动程序流支持:


来源:

我的猜测是,因为您忽略了
runForeach
的返回值,您看不到它是未来的,因此,在处理有机会执行之前,system.shutdown和db.close会立即关闭流(Akka流是异步的),如果显式传递Actormatarializer,则无需将其设为隐式,反之亦然。:)谢谢,维克托克朗。你能提交一个答案让我接受吗?这不是仍然会把所有的行都放到内存中吗?
def main(args: Array[String]) : Unit = {
  implicit val system = ActorSystem("Subscriber")
  implicit val materializer = ActorMaterializer()

  val strm = TableQuery[Streams]
  val db = Database.forConfig("pg-postgres")

  try{
    val src = Source.fromPublisher(db.stream(strm.result))
    val flow = src.to(Sink.fromSubscriber(new MyStreamWriter()))
    flow.run()
  } finally {
    system.shutdown
    db.close
  }
}
def enableStream(statement: java.sql.Statement): Unit = {
  statement match {
    case s: com.mysql.jdbc.StatementImpl => s.enableStreamingResults()
    case _ =>
  }
}

val publisher = sourceDb.stream(query.result.withStatementParameters(statementInit = enableStream))