Scala Slick:永无止境的溪流
使用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表中的所有事件,并在最后一行之后终止 假设在事件表中输入新行时可
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。当复制粘贴代码时,忘记了这一点:)不客气!