Play Framework:“连接太多”数据库错误

Posted

技术标签:

【中文标题】Play Framework:“连接太多”数据库错误【英文标题】:Play Framework: "too many connections" database error 【发布时间】:2018-08-02 22:44:41 【问题描述】:

播放框架 2.6,Postgresql。 Jooq 作为数据库访问库。

运行测试时,我得到了

org.postgresql.util.PSQLException: FATAL: 抱歉,客户端太多 已经

这是一个帮助类,它提供了 jooq 的 dsl 上下文:

@Singleton
class Db @Inject() (val db: Database, system: ActorSystem) 

  val databaseContext: ExecutionContext = system.dispatchers.lookup("contexts.database")

  def query[A](block: DSLContext => A): Future[A] = Future 
    db.withConnection  connection: Connection =>
      val dsl = DSL.using(connection, SQLDialect.POSTGRES_9_4)
      block(dsl)
    
  (databaseContext)

  def withTransaction[A](block: DSLContext => A): Future[A] = Future 
    db.withTransaction  connection: Connection =>
      val dsl: DSLContext = DSL.using(connection, SQLDialect.POSTGRES_9_4)
      block(dsl)
    
  (databaseContext)

我在这样的存储库中使用这个帮助类:

db.query  dsl =>
      val records = dsl
        .selectFrom(USERS)
        .where(...)
        ...  
      
    

application.conf

db.default.driver="org.postgresql.Driver"
db.default.url="jdbc:postgresql://localhost/postgres?user=postgres"

    ...
contexts  
    database 
        executor = "thread-pool-executor"
        throughput = 1
        thread-pool-executor 
          fixed-pool-size = 9
        
    

...

build.sbt

...
libraryDependencies += jdbc
libraryDependencies += "org.jooq" % "jooq" % "3.10.5"
libraryDependencies += "org.jooq" % "jooq-codegen-maven" % "3.10.5"
libraryDependencies += "org.jooq" % "jooq-meta" % "3.10.5"
libraryDependencies += "org.postgresql" % "postgresql" % "42.1.4"
...

以及我所有测试的基本特征:

class BaseFeatureSpec extends FeatureSpec
  with GivenWhenThen
  with GuiceOneServerPerSuite
  with Matchers
  with WsScalaTestClient
  with BeforeAndAfterEach
  with MockitoSugar 

  override def fakeApplication(): Application =
    new GuiceApplicationBuilder()
      .overrides(bind[EmailService].to(classOf[EmailServiceStub]))
      .build()

  def config: Configuration = fakeApplication().configuration
  def actorSystem: ActorSystem = fakeApplication().actorSystem

  val db: Db = app.injector.instanceOf[Db]

  val wsClient: WSClient = app.injector.instanceOf[WSClient]
  val myPublicAddress = s"localhost:$port"

  private val injector = fakeApplication().injector

  def truncateDbOnEachRun = true

  override protected def beforeEach(): Unit = 
    if (truncateDbOnEachRun) 
      truncateDb
    
  

   protected def truncateDb = 
    await(db.withTransaction  dsl =>
      ... truncate all dbs...
    )
  

我的 postgresql 实例的最大连接数是 100。

我注意到,在运行测试时,我发现池几乎在每次测试之前都被创建了多次:

[info] application - Creating Pool for datasource 'default'
[info] application - Creating Pool for datasource 'default'
[info] application - Creating Pool for datasource 'default'
[info] application - Creating Pool for datasource 'default'

在我收到 too many connections 错误之后。

请帮忙。

【问题讨论】:

您要测试应用的哪个部分? 我正在测试整个应用程序(与真实 Web 服务器的集成测试),每个测试都测试 http 端点,这些端点又将所有层调用到 db。为什么? 我在 jOOQ 方面看不到您的代码有任何问题,因此我认为问题与您如何配置该数据源有关... 【参考方案1】:

你好像使用了一个默认类型的dispatcher,尝试添加type = PinnedDispatcher,用于io类型的dispatcher,如下。

thread-pool-executor 
  ...
  type = PinnedDispatcher

您可以从以下位置找到详细信息 https://doc.akka.io/docs/akka/2.5/dispatchers.html

【讨论】:

【参考方案2】:

我发现了问题:

override def fakeApplication(): Application =
    new GuiceApplicationBuilder()
      .overrides(bind[EmailService].to(classOf[EmailServiceStub]))
      .build()

每次我像app.injector.instanceOf[Db] 一样访问它时都会创建新的应用程序实例(因为它是方法),所以这就是我有这么多application - Creating Pool for datasource 'default' 日志的原因。

我已将def 替换为val

override val fakeApplication(): Application =
        new GuiceApplicationBuilder()
          .overrides(bind[EmailService].to(classOf[EmailServiceStub]))
          .build()

而且效果很好。

【讨论】:

以上是关于Play Framework:“连接太多”数据库错误的主要内容,如果未能解决你的问题,请参考以下文章

Play Framework 2.3 - 无法连接到远程数据库 Linux (Play) -> Win 7 (MySQL)

Play Framework:数据库连接池关闭

Play framework 2.0.1 不断尝试进化错误的数据库类型

如何使用 Play Framework 显示 SQL?

java 如何使用Play Framework 2.5测试具有多部分数据的路径

如何使用 Play Framework 的 SBT 下载 Maxmind 数据库