【问题标题】:Conflict between Hikari, Quill, and Postgres in the conf file for Play 2.6Play 2.6 的 conf 文件中 Hikari、Quill 和 Postgres 之间的冲突
【发布时间】:2018-08-11 00:34:43
【问题描述】:

我在运行 Play 应用程序时遇到了一个奇怪的错误(这似乎是我现在的生活故事)。前几天,我遇到this issue,解决了这个问题,能够运行进化并创建表格,然后遇到以下问题:

java.lang.RuntimeException: Property driver does not exist on target class com.zaxxer.hikari.HikariConfig

这是我当前 application.conf 中的相关部分:

db.default {
    dataSourceClassName = org.postgresql.ds.PGSimpleDataSource
    url = "jdbc:postgresql://localhost:5432/app-users?user=root&password=root"
    driver = org.postgresql.Driver
    username = root
    password = root
    databaseName = app-users
    portNumber = 5432
    serverName = localhost
    connectionTimeout = 30000
}

我做了some digging 并发现Hikari 期望driverClassName(以及其他一些差异)。 Hikari docsQuill docs 说这样的东西应该在 application.conf 中:

dataSourceClassName=org.postgresql.ds.PGSimpleDataSource
dataSource.user=root
dataSource.password=root
dataSource.databaseName=app-users
dataSource.portNumber=5432
dataSource.serverName=localhost

但是,当我拥有它时,进化将无法运行。他们只会在我现在拥有它时运行。由于进化正在运行,它似乎正在连接到数据库。那么为什么我会收到一条消息说它不能呢?有没有办法让我为 Hikari 和 Postgres/Quill 提供单独的数据库配置?

完整的错误信息:

play.api.UnexpectedException: Unexpected exception[IllegalStateException: Failed to load data source for config: 'Config(SimpleConfigObject({"connectionTimeout":30000,"dataSourceClassName":"org.postgresql.ds.PGSimpleDataSource","databaseName":"mack-users","driver":"org.postgresql.Driver","password":"root","portNumber":5432,"serverName":"localhost","url":"jdbc:postgresql://localhost:5432/mack-users?user=root&password=root","username":"root"}))']
    at play.core.server.DevServerStart$$anon$1.reload(DevServerStart.scala:186)
    at play.core.server.DevServerStart$$anon$1.get(DevServerStart.scala:124)
    at play.core.server.AkkaHttpServer.modelConversion(AkkaHttpServer.scala:183)
    at play.core.server.AkkaHttpServer.handleRequest(AkkaHttpServer.scala:189)
    at play.core.server.AkkaHttpServer.$anonfun$createServerBinding$3(AkkaHttpServer.scala:106)
    at akka.stream.impl.fusing.MapAsync$$anon$24.onPush(Ops.scala:1191)
    at akka.stream.impl.fusing.GraphInterpreter.processPush(GraphInterpreter.scala:512)
    at akka.stream.impl.fusing.GraphInterpreter.processEvent(GraphInterpreter.scala:475)
    at akka.stream.impl.fusing.GraphInterpreter.execute(GraphInterpreter.scala:371)
    at akka.stream.impl.fusing.GraphInterpreterShell.runBatch(ActorGraphInterpreter.scala:584)
Caused by: java.lang.IllegalStateException: Failed to load data source for config: 'Config(SimpleConfigObject({"connectionTimeout":30000,"dataSourceClassName":"org.postgresql.ds.PGSimpleDataSource","databaseName":"mack-users","driver":"org.postgresql.Driver","password":"root","portNumber":5432,"serverName":"localhost","url":"jdbc:postgresql://localhost:5432/mack-users?user=root&password=root","username":"root"}))'
    at io.getquill.JdbcContextConfig.dataSource(JdbcContextConfig.scala:24)
    at io.getquill.PostgresJdbcContext.<init>(PostgresJdbcContext.scala:17)
    at io.getquill.PostgresJdbcContext.<init>(PostgresJdbcContext.scala:18)
    at io.getquill.PostgresJdbcContext.<init>(PostgresJdbcContext.scala:19)
    at db.db.package$DBContext.<init>(package.scala:6)
    at MyComponents.ctx$lzycompute(MyApplicationLoader.scala:25)
    at MyComponents.ctx(MyApplicationLoader.scala:25)
    at MyComponents.userService$lzycompute(MyApplicationLoader.scala:28)
    at MyComponents.userService(MyApplicationLoader.scala:28)
    at MyComponents.applicationController$lzycompute(MyApplicationLoader.scala:35)
Caused by: java.lang.RuntimeException: Property driver does not exist on target class com.zaxxer.hikari.HikariConfig
    at com.zaxxer.hikari.util.PropertyElf.setProperty(PropertyElf.java:131)
    at com.zaxxer.hikari.util.PropertyElf.lambda$setTargetFromProperties$0(PropertyElf.java:57)
    at java.util.Hashtable.forEach(Hashtable.java:879)
    at com.zaxxer.hikari.util.PropertyElf.setTargetFromProperties(PropertyElf.java:52)
    at com.zaxxer.hikari.HikariConfig.<init>(HikariConfig.java:132)
    at io.getquill.JdbcContextConfig.dataSource(JdbcContextConfig.scala:21)
    at io.getquill.PostgresJdbcContext.<init>(PostgresJdbcContext.scala:17)
    at io.getquill.PostgresJdbcContext.<init>(PostgresJdbcContext.scala:18)
    at io.getquill.PostgresJdbcContext.<init>(PostgresJdbcContext.scala:19)
    at db.db.package$DBContext.<init>(package.scala:6)

db/package.scala

import io.getquill.{PostgresJdbcContext, SnakeCase}

package object db {
  class DBContext(config: String) extends PostgresJdbcContext(SnakeCase, config)

  trait Repository {
    val ctx: DBContext
  }
}

关于什么可能导致这种情况的任何想法?或者我错过了什么?

使用:

  • Scala 2.12.4
  • 羽毛笔 2.3.2
  • 播放 2.6.6
  • Postgres JDBC 驱动程序 42.2.1
  • PostgreSQL 10.2

当我输入 Quill/Hikari 期望的内容时出现错误消息:

! @776d39n6c - Internal server error, for (GET) [/] ->

play.api.Configuration$$anon$1: Configuration error[Cannot connect to database [default]]
    at play.api.Configuration$.configError(Configuration.scala:156)
    at play.api.Configuration.reportError(Configuration.scala:990)
    at play.api.db.DefaultDBApi.$anonfun$connect$1(DefaultDBApi.scala:48)
    at play.api.db.DefaultDBApi.$anonfun$connect$1$adapted(DefaultDBApi.scala:42)
    at scala.collection.immutable.List.foreach(List.scala:389)
    at play.api.db.DefaultDBApi.connect(DefaultDBApi.scala:42)
    at play.api.db.DBApiProvider.get$lzycompute(DBModule.scala:86)
    at play.api.db.DBApiProvider.get(DBModule.scala:75)
    at play.api.db.DBComponents.dbApi(DBModule.scala:49)
    at play.api.db.DBComponents.dbApi$(DBModule.scala:49)
Caused by: play.api.Configuration$$anon$1: Configuration error[dataSource or dataSourceClassName or jdbcUrl is required.]
    at play.api.Configuration$.configError(Configuration.scala:156)
    at play.api.Configuration.reportError(Configuration.scala:990)
    at play.api.db.HikariCPConnectionPool.create(HikariCPModule.scala:63)
    at play.api.db.PooledDatabase.createDataSource(Databases.scala:199)
    at play.api.db.DefaultDatabase.dataSource$lzycompute(Databases.scala:123)
    at play.api.db.DefaultDatabase.dataSource(Databases.scala:121)
    at play.api.db.DefaultDatabase.getConnection(Databases.scala:142)
    at play.api.db.DefaultDatabase.getConnection(Databases.scala:138)
    at play.api.db.DefaultDBApi.$anonfun$connect$1(DefaultDBApi.scala:44)
    at play.api.db.DefaultDBApi.$anonfun$connect$1$adapted(DefaultDBApi.scala:42)
Caused by: java.lang.IllegalArgumentException: dataSource or dataSourceClassName or jdbcUrl is required.
    at com.zaxxer.hikari.HikariConfig.validate(HikariConfig.java:997)
    at play.api.db.HikariCPConfig.toHikariConfig(HikariCPModule.scala:136)
    at play.api.db.HikariCPConnectionPool.$anonfun$create$1(HikariCPModule.scala:50)
    at scala.util.Try$.apply(Try.scala:209)
    at play.api.db.HikariCPConnectionPool.create(HikariCPModule.scala:47)
    at play.api.db.PooledDatabase.createDataSource(Databases.scala:199)
    at play.api.db.DefaultDatabase.dataSource$lzycompute(Databases.scala:123)
    at play.api.db.DefaultDatabase.dataSource(Databases.scala:121)
    at play.api.db.DefaultDatabase.getConnection(Databases.scala:142)
    at play.api.db.DefaultDatabase.getConnection(Databases.scala:138)

【问题讨论】:

  • 当您将 quill 想要的内容放入 application.conf 时,您是否遇到任何错误,或者进化根本无法运行?另外你如何创建你的 jdbc 上下文?我们使用@Singleton class DefaultDbContext extends PostgresJdbcContext[SnakeCase](SnakeCase, "ctx") 之类的东西,这意味着我们在每个配置参数前面加上ctx,所以ctx.dataSourceClassName - 不确定,但也许这可以解决任何冲突。
  • @MattFowler 当我将 Quill 想要的内容放入 application.conf 并且进化没有运行时,我确实得到了一个不同的错误。我将使用该错误消息和 jdbc 上下文更新问题。
  • 实际上从文档中我认为 Quill 期望 application.properties(使用 Java 属性格式)和 Play(我猜使用 Slick)需要使用 HOCON 格式的 application.conf。我想,如果您同时提供了这两个文件,它就可以工作 - 在弄清楚如何为这两个文件使用一个配置之前,这将是一个不错的后备选项。

标签: postgresql scala playframework hikaricp quill.io


【解决方案1】:

不幸的是,Hikari 和 Play 并没有使用完全相同的命名约定来设置它们的数据源,例如,Quill 需要一个裸露的 dataSourceClassName,但 Play 需要像 db.default.dataSourceClassName 这样的格式。据我所知,没有办法重新设计您的配置以使其同时满足它们,您可能不希望这样做,原因如下:

Play 实际上使用 Hikari 作为池数据源,因此当您通过 db.default 创建数据库时,您实际上已经创建了池数据源。当您使用裸配置调用 PostgresJdbcContext 时,您实际上是在要求 Quill 创建一个完全独立的连接池。不确定这是否是您想要的,但我假设您只需要一个连接池。

Quill 实际上公开了一个接受DataSource 的构造函数,因此您可以使用Play 创建的Database 并将其直接传递给Quill:

import io.getquill.{PostgresJdbcContext, SnakeCase}
import com.zaxxer.hikari.HikariDataSource
import play.api.db.Database

package object db {
    class DBContext(db: Database) extends PostgresJdbcContext(SnakeCase, db.dataSource.asInstanceOf[HikariDataSource])
}

这应该可以解决您的问题,并且只会创建一个连接池。您可以通过依赖注入获得Database 对象。

你必须在这里做一个丑陋的asInstanceOf,因为PostgresJdbcContext需要dataSource来实现Closeable,而裸DataSource类没有实现。我遇到了类似的问题,但没有找到更优雅的方法。

【讨论】:

  • 谢谢!还有一个问题:如果我按照您的建议进行更新,我将如何在代码中稍后初始化 DBContext? val ctx = new DBContext(???)
  • @jmkoni 我会考虑让依赖注入为你处理事情。如果您创建了这样的类:@Singleton class DBContext @Inject()(db: Database) extends PostgresJdbcContext(SnakeCase, db.dataSource.asInstanceOf[HikariDataSource]) 那么在任何需要 DBContext 的控制器中,您只需执行以下操作:@Singleton class MyController @Inject() (cc: ControllerComponents, dbContext: DBContext) 并且您不需要自己直接创建 DBContext。
猜你喜欢
  • 2011-07-03
  • 2016-06-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-07-25
  • 1970-01-01
  • 2019-02-14
相关资源
最近更新 更多