【问题标题】:All connection pools fail to initialize when one connection pool fails to initialize一个连接池初始化失败时所有连接池初始化失败
【发布时间】:2018-04-25 02:46:28
【问题描述】:

这是一个错误吗?

我将 Playframework 2.6.6 与 scala 2.12.3 一起使用。我在 application.conf 中定义了 3 个数据库(hikaricp 连接池的设置遍布地图,因为我对它们进行了实验):

db {
  mentions {
    driver="org.postgresql.Driver"
    url="jdbc:postgresql://localhost:5432/mentions"
    password="***"
    username="play"
    hikaricp {
      maximumPoolSize = 2
      minimumIdle=2
    }

  }

  postgres {
    driver="org.postgresql.Driver"
    url="jdbc:postgresql://localhost:5432/postgres"
    password="***"
    username="postgres"
    hikaricp {
      maximumPoolSize = 9
      minimumIdle=9
    }
  }

  sqlserver {
    driver="net.sourceforge.jtds.jdbc.Driver"
    url="jdbc:jtds:sqlserver://10.211.55.5:1433/db"
    username="sa"
    password="***"
    hikaricp {
      maximumPoolSize=4
      minimumIdle=4
      //connectionTestQuery="select 1"
    }
  }

}

使用此配置,Hikaricp 连接池无法初始化 sql server 连接池,实际上其他两个连接池都没有初始化。 sql server连接错误的修复方法是设置connectionTestQuery。这不是这篇文章的重点。我不明白为什么当这个连接失败时其他两个连接会失败。在我看来,其他两个连接池应该仍然有效。

以下是来自控制台的错误消息:

[info] application - Creating Pool for datasource 'sqlserver'
[error] c.z.h.p.PoolBase - HikariPool-1 - Failed to execute isValid() for connection, configure connection test query (null).
[info] application - Creating Pool for datasource 'sqlserver'
[error] c.z.h.p.PoolBase - HikariPool-2 - Failed to execute isValid() for connection, configure connection test query (null).
[info] application - Creating Pool for datasource 'sqlserver'
[error] c.z.h.p.PoolBase - HikariPool-3 - Failed to execute isValid() for connection, configure connection test query (null).
[error] application - 

! @761fipg95 - Internal server error, for (GET) [/] ->

play.api.UnexpectedException: Unexpected exception[CreationException: Unable to create injector, see the following errors:

1) Error injecting method, java.lang.AbstractMethodError
  at com.google.inject.util.Providers$GuicifiedProviderWithDependencies.initialize(Providers.java:149)
  at play.api.db.DBModule$$anonfun$$lessinit$greater$1.$anonfun$new$1(DBModule.scala:25):
Binding(interface play.api.db.Database qualified with QualifierInstance(@play.db.NamedDatabase(value=sqlserver)) to ProviderTarget(play.api.db.NamedDatabaseProvider@65c05a8b)) (via modules: com.google.inject.util.Modules$OverrideModule -> play.api.inject.guice.GuiceableModuleConversions$$anon$1)

2) Error injecting method, java.lang.AbstractMethodError
  at com.google.inject.util.Providers$GuicifiedProviderWithDependencies.initialize(Providers.java:149)
  at play.api.db.DBModule$$anonfun$$lessinit$greater$1.$anonfun$new$1(DBModule.scala:25):
Binding(interface play.api.db.Database qualified with QualifierInstance(@play.db.NamedDatabase(value=mentions)) to ProviderTarget(play.api.db.NamedDatabaseProvider@700c1d35)) (via modules: com.google.inject.util.Modules$OverrideModule -> play.api.inject.guice.GuiceableModuleConversions$$anon$1)

3) Error injecting method, java.lang.AbstractMethodError
  at com.google.inject.util.Providers$GuicifiedProviderWithDependencies.initialize(Providers.java:149)
  at play.api.db.DBModule$$anonfun$$lessinit$greater$1.$anonfun$new$1(DBModule.scala:25):
Binding(interface play.api.db.Database qualified with QualifierInstance(@play.db.NamedDatabase(value=postgres)) to ProviderTarget(play.api.db.NamedDatabaseProvider@1f4f0047)) (via modules: com.google.inject.util.Modules$OverrideModule -> play.api.inject.guice.GuiceableModuleConversions$$anon$1)

3 errors]
    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$23.onPush(Ops.scala:1172)
    at akka.stream.impl.fusing.GraphInterpreter.processPush(GraphInterpreter.scala:499)
    at akka.stream.impl.fusing.GraphInterpreter.processEvent(GraphInterpreter.scala:462)
    at akka.stream.impl.fusing.GraphInterpreter.execute(GraphInterpreter.scala:368)
    at akka.stream.impl.fusing.GraphInterpreterShell.runBatch(ActorGraphInterpreter.scala:571)
Caused by: com.google.inject.CreationException: Unable to create injector, see the following errors:

1) Error injecting method, java.lang.AbstractMethodError
  at com.google.inject.util.Providers$GuicifiedProviderWithDependencies.initialize(Providers.java:149)
  at play.api.db.DBModule$$anonfun$$lessinit$greater$1.$anonfun$new$1(DBModule.scala:25):
Binding(interface play.api.db.Database qualified with QualifierInstance(@play.db.NamedDatabase(value=sqlserver)) to ProviderTarget(play.api.db.NamedDatabaseProvider@65c05a8b)) (via modules: com.google.inject.util.Modules$OverrideModule -> play.api.inject.guice.GuiceableModuleConversions$$anon$1)

2) Error injecting method, java.lang.AbstractMethodError
  at com.google.inject.util.Providers$GuicifiedProviderWithDependencies.initialize(Providers.java:149)
  at play.api.db.DBModule$$anonfun$$lessinit$greater$1.$anonfun$new$1(DBModule.scala:25):
Binding(interface play.api.db.Database qualified with QualifierInstance(@play.db.NamedDatabase(value=mentions)) to ProviderTarget(play.api.db.NamedDatabaseProvider@700c1d35)) (via modules: com.google.inject.util.Modules$OverrideModule -> play.api.inject.guice.GuiceableModuleConversions$$anon$1)

3) Error injecting method, java.lang.AbstractMethodError
  at com.google.inject.util.Providers$GuicifiedProviderWithDependencies.initialize(Providers.java:149)
  at play.api.db.DBModule$$anonfun$$lessinit$greater$1.$anonfun$new$1(DBModule.scala:25):
Binding(interface play.api.db.Database qualified with QualifierInstance(@play.db.NamedDatabase(value=postgres)) to ProviderTarget(play.api.db.NamedDatabaseProvider@1f4f0047)) (via modules: com.google.inject.util.Modules$OverrideModule -> play.api.inject.guice.GuiceableModuleConversions$$anon$1)

3 errors
    at com.google.inject.internal.Errors.throwCreationExceptionIfErrorsExist(Errors.java:470)
    at com.google.inject.internal.InternalInjectorCreator.injectDynamically(InternalInjectorCreator.java:176)
    at com.google.inject.internal.InternalInjectorCreator.build(InternalInjectorCreator.java:110)
    at com.google.inject.Guice.createInjector(Guice.java:99)
    at com.google.inject.Guice.createInjector(Guice.java:84)
    at play.api.inject.guice.GuiceBuilder.injector(GuiceInjectorBuilder.scala:185)
    at play.api.inject.guice.GuiceApplicationBuilder.build(GuiceApplicationBuilder.scala:137)
    at play.api.inject.guice.GuiceApplicationLoader.load(GuiceApplicationLoader.scala:21)
    at play.core.server.DevServerStart$$anon$1.$anonfun$reload$3(DevServerStart.scala:174)
    at play.utils.Threads$.withContextClassLoader(Threads.scala:21)
Caused by: java.lang.AbstractMethodError: null
    at net.sourceforge.jtds.jdbc.JtdsConnection.isValid(JtdsConnection.java:2833)
    at com.zaxxer.hikari.pool.PoolBase.checkDriverSupport(PoolBase.java:456)
    at com.zaxxer.hikari.pool.PoolBase.setupConnection(PoolBase.java:423)
    at com.zaxxer.hikari.pool.PoolBase.newConnection(PoolBase.java:381)
    at com.zaxxer.hikari.pool.PoolBase.newPoolEntry(PoolBase.java:205)
    at com.zaxxer.hikari.pool.HikariPool.createPoolEntry(HikariPool.java:448)
    at com.zaxxer.hikari.pool.HikariPool.checkFailFast(HikariPool.java:519)
    at com.zaxxer.hikari.pool.HikariPool.<init>(HikariPool.java:113)
    at com.zaxxer.hikari.HikariDataSource.<init>(HikariDataSource.java:72)
    at play.api.db.HikariCPConnectionPool.$anonfun$create$1(HikariCPModule.scala:51)

更新:我仍然认为在架构上,如果一个连接池不起作用,其他连接池不应该受到影响。今天我关闭了运行 sql server 的 windows vm,我只运行了我的 postgresql 服务器。我测试的页面只连接到 postgresql dbs,它仍然失败,因为 sql server 连接池不起作用。这次它失败并出现配置错误 java.sql.SQLException - Login Timed out。

【问题讨论】:

    标签: scala jdbc playframework


    【解决方案1】:

    在 2.6.6 和 2.6.7 中进行了一些调试后,我发现了以下内容:

    java.lang.AbstractMethodError 继承 java.lang.IncompatibleClassChangeError 继承 java.lang.LinkageError。 java.lang.LinkageError 根据 NonFatal 对象被认为是致命的:

    object NonFatal {
       /**
        * Returns true if the provided `Throwable` is to be considered non-fatal, or false if it is to be considered fatal
        */
       def apply(t: Throwable): Boolean = t match {
         // VirtualMachineError includes OutOfMemoryError and other fatal errors
         case _: VirtualMachineError | _: ThreadDeath | _: InterruptedException | _: LinkageError | _: ControlThrowable => false
         case _ => true
       }
      /**
       * Returns Some(t) if NonFatal(t) == true, otherwise None
       */
      def unapply(t: Throwable): Option[Throwable] = if (apply(t)) Some(t) else None
    }
    

    因此,遍布代码的 Try 调用不会捕获此异常。

    异常最终由 guice 层处理。该调用返回到 guice Initializer.injectAll 方法,该方法(在其他对象中)为 application.conf 文件中配置的每个数据库连接注入 NamedDatabaseProvider 对象(与 NamedDatabaseProvider 的绑定在 DBModule 中连接)。 NamedDatabaseProvider 对象依赖于 DBApi,其每次初始化都会由于被认为是致命的 AbstractMethodError 异常而失败。

    最终问题是多种情况的组合:1. Hikaricp 代码中抛出的异常是致命的,2. DBApi 代码想要初始化所有连接池并且它不处理致命错误。

    我不认为这是一个错误。也许 Hickaricp 家伙可能会抛出 UnsupportedOperationException 或 similar

    对于其他感兴趣的人,我发现了这个:https://github.com/njlg/playdb

    【讨论】:

      猜你喜欢
      • 2015-08-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-03-03
      相关资源
      最近更新 更多