Scala + Play Framework + Slick + Akka - 来自Akka Actor的数据库访问

emm*_*a90 4 scala akka playframework slick

在接收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")
    }
Run Code Online (Sandbox Code Playgroud)

Tcp服务器是接收消息的actor,需要将其推送到DB Actor上

      val handler = context.actorSelection("/dbActor")
Run Code Online (Sandbox Code Playgroud)

根据Play Framework规范,DB actor以这种方式初始化

    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 }
        }
      }
    }
Run Code Online (Sandbox Code Playgroud)

目前,演员不是由于错误而构建的

    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)
Run Code Online (Sandbox Code Playgroud)

所以我需要一种方法在DBactor中注入db配置来查询数据库或替代方案.我之前评估过注入DAO或将我需要的DAO转换为演员,两者都失败了.

此时的问题是,让演员访问数据库或者至少是控制器是否有意义?如果无法做到,有哪些替代方案?

ret*_*hab 6

你需要的是一个注入的演员.完整的描述可以在播放文档(https://www.playframework.com/documentation/2.5.x/ScalaAkka#Dependency-injecting-actors)中找到,但这里是它的要点:

您可以像这样定义actor绑定:

bindActor[DBActor]("db-actor")
Run Code Online (Sandbox Code Playgroud)

并在控制器中注入actor,如下所示:

class Application @Inject() (@Named("db-actor") dbActor: ActorRef) extends Controller {
Run Code Online (Sandbox Code Playgroud)

另外一点,你应该Await.result尽可能避免.在您的方案中,这可能很容易被替换为:

val senderRef = sender()
db.run(table.filter(_.id=== id).result.headOption)
  .map(res => senderRef ! res.config)
Run Code Online (Sandbox Code Playgroud)

请注意,之前存储发送者引用,因为它在内部不再有效map(请参阅sender()方法的scaladoc ).