Scala + Play Framework + Slick + Like - Like Actor 的数据库访问
Scala + Play Framework + Slick + Akka - DB Access from Akka Actor
在收到 TCP 特定消息时,我需要查询我的数据库。为此,我创建了一个名为 DBActor 的 Actor 并将其加载到 Application.scala
文件
class Application @Inject() (system: ActorSystem) extends Controller {
val tcpServer = system.actorOf(Props[TCPServer], "tcpserver")
val dbActor = system.actorOf(Props[DBActor], "dbActor")
}
Tcp 服务器是接收消息的 actor,需要将其推送到 DB Actor 上
val handler = context.actorSelection("/dbActor")
DB actor是这样初始化的,根据Play Framework规范
object DBActor {
def props() =
Props(classOf[DBActor])
}
class DBActor @Inject() (protected val dbConfigProvider:
DatabaseConfigProvider) extends Actor
with HasDatabaseConfigProvider[JdbcProfile]
with ActorLogging
with TableComponent {
import akka.io.Tcp._
import driver.api._
val table = TableQuery[Table]
def receive: Receive = {
case GetConfig(id) => {
sender ! Await.result(db.run(table.filter(_.id=== id).result.headOption),
Duration.Inf)
.map { x => x.config }
}
}
}
目前,由于错误,actor 未构建
Error injecting constructor, java.lang.IllegalArgumentException:
no matching constructor found on class tcp.DBActor for arguments []
at controllers.Application.<init>(Application.scala:17)
at controllers.Application.class(Application.scala:17)
所以我需要一种方法来在 DBactor 中注入数据库配置以查询数据库或替代方法。我之前评估过注入一个DAO或者将我需要的DAO转化为一个actor,都失败了。
此时的问题是,让参与者访问数据库或至少访问控制器是否有意义?如果做不到,有什么替代方案?
你需要的是一个注入的actor。完整的描述可以在播放文档 (https://www.playframework.com/documentation/2.5.x/ScalaAkka#Dependency-injecting-actors) 中找到,但这里是它的要点:
您可以像这样定义 actor 绑定:
bindActor[DBActor]("db-actor")
然后像这样在控制器中注入 actor:
class Application @Inject() (@Named("db-actor") dbActor: ActorRef) extends Controller {
换句话说,您应该尽可能避免 Await.result
。在您的场景中,这可能很容易替换为:
val senderRef = sender()
db.run(table.filter(_.id=== id).result.headOption)
.map(res => senderRef ! res.config)
注意之前存储了sender ref,因为在map
内部已经失效了(见sender()
方法的scaladoc)
在收到 TCP 特定消息时,我需要查询我的数据库。为此,我创建了一个名为 DBActor 的 Actor 并将其加载到 Application.scala
文件
class Application @Inject() (system: ActorSystem) extends Controller {
val tcpServer = system.actorOf(Props[TCPServer], "tcpserver")
val dbActor = system.actorOf(Props[DBActor], "dbActor")
}
Tcp 服务器是接收消息的 actor,需要将其推送到 DB Actor 上
val handler = context.actorSelection("/dbActor")
DB actor是这样初始化的,根据Play Framework规范
object DBActor {
def props() =
Props(classOf[DBActor])
}
class DBActor @Inject() (protected val dbConfigProvider:
DatabaseConfigProvider) extends Actor
with HasDatabaseConfigProvider[JdbcProfile]
with ActorLogging
with TableComponent {
import akka.io.Tcp._
import driver.api._
val table = TableQuery[Table]
def receive: Receive = {
case GetConfig(id) => {
sender ! Await.result(db.run(table.filter(_.id=== id).result.headOption),
Duration.Inf)
.map { x => x.config }
}
}
}
目前,由于错误,actor 未构建
Error injecting constructor, java.lang.IllegalArgumentException:
no matching constructor found on class tcp.DBActor for arguments []
at controllers.Application.<init>(Application.scala:17)
at controllers.Application.class(Application.scala:17)
所以我需要一种方法来在 DBactor 中注入数据库配置以查询数据库或替代方法。我之前评估过注入一个DAO或者将我需要的DAO转化为一个actor,都失败了。
此时的问题是,让参与者访问数据库或至少访问控制器是否有意义?如果做不到,有什么替代方案?
你需要的是一个注入的actor。完整的描述可以在播放文档 (https://www.playframework.com/documentation/2.5.x/ScalaAkka#Dependency-injecting-actors) 中找到,但这里是它的要点:
您可以像这样定义 actor 绑定:
bindActor[DBActor]("db-actor")
然后像这样在控制器中注入 actor:
class Application @Inject() (@Named("db-actor") dbActor: ActorRef) extends Controller {
换句话说,您应该尽可能避免 Await.result
。在您的场景中,这可能很容易替换为:
val senderRef = sender()
db.run(table.filter(_.id=== id).result.headOption)
.map(res => senderRef ! res.config)
注意之前存储了sender ref,因为在map
内部已经失效了(见sender()
方法的scaladoc)