Scala Slick:永无止境的溪流

Scala Slick:永无止境的溪流,scala,slick,akka-stream,reactive-streams,Scala,Slick,Akka Stream,Reactive Streams,使用Slick,您可以执行以下操作,从表中生成一系列结果: val q = for (e <- events) yield e.name val p: DatabasePublisher[String] = db.stream(q.result) p.foreach { s => println(s"Event: $s") } val q=for(e println(s“Event:$s”)} 这将打印events表中的所有事件,并在最后一行之后终止 假设在事件表中输入新行时可

使用Slick,您可以执行以下操作,从表中生成一系列结果:

val q = for (e <- events) yield e.name
val p: DatabasePublisher[String] = db.stream(q.result)

p.foreach { s => println(s"Event: $s") }
val q=for(e println(s“Event:$s”)}
这将打印
events
表中的所有事件,并在最后一行之后终止

假设在
事件
表中输入新行时可以以某种方式通知您,那么是否可以编写一个流,在插入事件时连续输出事件?对于DB表来说,这是一种
尾-f

我认为Slick本机不支持这一点,但我认为应该可以使用Akka streaming来提供帮助。因此,如果您可以从Slick源中获取一些内容,直到其为空,然后等待事件指示表中的更多数据,然后流式传输新数据。可能可以使用
ActorPublisher
绑定此登录c


只是想知道是否有人在这方面有任何经验或建议?

您对ActorPublisher的看法是正确的:)下面是一个使用PostgreSQL的简单示例,以及:

演员:

class PostgresListener extends ActorPublisher[String] {

  override def receive = {
    case _ ⇒
      val configuration = URLParser.parse(s"jdbc://postgresql://$host:$port/$db?user=$user&password=$password")
      val connection = new PostgreSQLConnection(configuration)
      Await.result(connection.connect, 5.seconds)

      connection.sendQuery(s"LISTEN $channel")
      connection.registerNotifyListener { message ⇒ onNext(message.payload) }
  }
}
服务:

def stream: Source[ServerSentEvent, Unit] = {
  val dataPublisherRef = Props[PostgresListener]
  val dataPublisher = ActorPublisher[String](dataPublisherRef)

  dataPublisherRef ! "go"

  Source(dataPublisher)
    .map(ServerSentEvent(_))
    .via(WithHeartbeats(10.second))
}
libraryDependencies
中的
build.sbt

"com.github.mauricio"  %% "postgresql-async"         % "0.2.18"
Postgres触发器应调用
选择pg\u notify('foo','payload')

据我所知,Slick不支持
LISTEN

自Akka 2.5.0以来一直被弃用。下面是一个使用库并在参与者内部创建

import akka.actor._
import akka.stream._
import akka.stream.scaladsl._

import com.github.mauricio.async.db.postgresql.PostgreSQLConnection
import com.github.mauricio.async.db.postgresql.util.URLParser

import scala.concurrent.duration._
import scala.concurrent.Await

class DbActor(implicit materializer: ActorMaterializer) extends Actor with ActorLogging {
  private implicit val ec = context.system.dispatcher

  val queue =  
    Source.queue[String](Int.MaxValue, OverflowStrategy.backpressure)
      .to(Sink.foreach(println))
      .run()

  val configuration = URLParser.parse("jdbc:postgresql://localhost:5233/my_db?user=dbuser&password=pwd")
  val connection = new PostgreSQLConnection(configuration)
  Await.result(connection.connect, 5 seconds)

  connection.sendQuery("LISTEN my_channel")
  connection.registerNotifyListener { message =>
    val msg = message.payload
    log.debug("Sending the payload: {}", msg)
    self ! msg
  }

  def receive = {
    case payload: String =>
      queue.offer(payload).pipeTo(self)
    case QueueOfferResult.Dropped =>
      log.warning("Dropped a message.")
    case QueueOfferResult.Enqueued =>
      log.debug("Enqueued a message.")
    case QueueOfferResult.Failure(t) =>
      log.error("Stream failed: {}", t.getMessage)
    case QueueOfferResult.QueueClosed =>
      log.debug("Stream closed.")
  }
}
上面的代码只是在PostgreSQL发出通知时打印它们;您可以用另一个
Sink
替换
Sink.foreach(println)
。要运行它,请执行以下操作:

import akka.actor._
import akka.stream.ActorMaterializer

object Example extends App {
  implicit val system = ActorSystem()
  implicit val materializer = ActorMaterializer()
  system.actorOf(Props(classOf[DbActor], materializer))
}

这感觉有点像Spark的数据流:我现在有了一些工作,与您的答案略有不同,但使用的是ActorPublisher,因此感谢您的确认。另外,我认为您的答案是使用来自akka sse项目的代码(ServerSentEvent/WithHeartbeats)?这对于这个问题来说是不必要的,但恰好是我想要的。所以,也谢谢你的指点!是的,你说得对,那是Akka,我通过SSE将数据从DB流到UI。当复制粘贴代码时,忘记了这一点:)不客气!