使用数据库进行测试:“连接过多" [英] Play tests with database: "Too many connections"

查看:21
本文介绍了使用数据库进行测试:“连接过多"的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

为了在 scalatest 中使用具有进化的数据库,我使用了默认 PlaySpec 的这个扩展,其灵感来自于 这个问题:

To have a database available in scalatest with evolutions I use this extension of the default PlaySpec inspired by this SO question:

trait ResetDbSpec extends PlaySpec with BeforeAndAfterAll {
  lazy val appBuilder = new GuiceApplicationBuilder()
  lazy val injector = appBuilder.injector()
  lazy val databaseApi = injector.instanceOf[DBApi]

  override def beforeAll() = {
    Evolutions.applyEvolutions(databaseApi.database("default"))
  }

  override def afterAll() = {
    Evolutions.cleanupEvolutions(databaseApi.database("default"))
    databaseApi.database("default").shutdown()
  }
}

它在套件开始时应用数据库演变,并在套件结束时恢复它们.一个测试看起来像

It applies database evolutions when the suite starts, and reverts them when the suite ends. A test then looks like

class ProjectsSpec extends ResetDbSpec with OneAppPerSuite { ...

在添加更多这样的测试后,我遇到了一些单独运行时成功的测试,但由于此错误而失败:

After adding more tests like this, I hit a point where some tests that succeed when I run them alone, fail with this error:

com.mysql.jdbc.exceptions.jdbc4.MySQLNonTransientConnectionException:数据源拒绝建立连接,来自服务器的消息:连接过多"

com.mysql.jdbc.exceptions.jdbc4.MySQLNonTransientConnectionException: Data source rejected establishment of connection, message from server: "Too many connections"

正如在上面的代码中看到的,我尝试添加该行

As can be see in the code above, I tried to add the line

databaseApi.database("default").shutdown()

afterAll() 中以减轻这种情况,但没有效果.我尝试不并行运行测试,但也没有效果.我在哪里打开数据库连接而不关闭它们,我应该在哪里调用 shutdown()?

in afterAll() to mitigate that, but it had no effect. I tried to not run tests in parallel, but no effect either. Where is it that I open db connections without closing them, and where should I call shutdown()?

注意我使用 Play 2.5.10 和 Slick 3.1.

推荐答案

虽然它不能解决连接泄漏的问题,但我终于设法解决了这个问题:

Although it does not answer to what is happening with the connections leakage, I finally managed to hack around this:

  1. jdbc 添加到您的 libraryDependencies,即使 Play-Slick 常见问题解答 告诉您不要这样做:

  1. Add jdbc to you libraryDependencies, even if the Play-Slick FAQ tells you not to do it:

# build.sbt
libraryDependencies += jdbc

重新启动 sbt 以考虑更改.在 IntelliJ 中,您也需要刷新项目.

Restart sbt to take changes into account. In IntelliJ, you will want to refresh the project, too.

禁用与 play-slick 冲突的 jdbc 模块(来源:这个 SO 答案):

Disable the jdbc module that is conflicting with play-slick (credits: this SO answer):

# application.conf
play.modules.disabled += "play.api.db.DBModule"

在同一个地方你应该已经配置了类似的东西

At the same place you should have already configured something like

slick {
  dbs {
    default {
      driver = "slick.driver.MySQLDriver$"
      db.driver = "com.mysql.jdbc.Driver"
      db.url = "jdbc:mysql://localhost/test"
      db.user = "sa"
      db.password = ""
    }
  }
}

  • 现在您可以使用 jdbc 中的 play.api.db.Databases 及其方法 withDatabase 来运行进化.

  • Now you can use play.api.db.Databases from jdbc and its method withDatabase to run the evolutions.

    import org.scalatest.BeforeAndAfterAll
    import org.scalatestplus.play.PlaySpec
    import play.api.db.{Database, Databases}
    import play.api.db.evolutions.Evolutions
    
    
    trait ResetDbSpec extends PlaySpec with BeforeAndAfterAll {
    
      /**
       * Here we use Databases.withDatabase to run evolutions without leaking connections.
       * It slows down the tests considerably, though.
       */
    
      private def withTestDatabase[T](block: Database => T) = {
        Databases.withDatabase(
          driver = "com.mysql.jdbc.Driver",
          url = "jdbc:mysql://localhost/test",
          name = "default",
          config = Map(
            "username" -> "sa",
            "password" -> ""
          )
        )(block)
      }
    
      override def beforeAll() = {
        withTestDatabase { database =>
          Evolutions.applyEvolutions(database)
        }
      }
    
      override def afterAll() = {
        withTestDatabase { database =>
          Evolutions.cleanupEvolutions(database)
        }
      }
    
    }
    

  • 最后,调用需要像这样重置数据库的测试:

  • Finally, call tests requiring a db reset like this:

    class MySpec extends ResetDbSpec {...}
    

  • 当然,在application.test.conf"和withDatabase() 中重复这个配置很糟糕,而且它混合了两种不同的 API,而不是谈论性能.它还在每个套件之前和之后添加了这一点,这很烦人:

    Of course it sucks repeating this config both in "application.test.conf" and in withDatabase(), plus it mixes two different APIs, not talking about performance. Also it adds this before and after each suite, which is annoying:

    [信息] 应用程序 - 为数据源默认"创建池
    [信息] 应用程序 - 关闭连接池.

    [info] application - Creating Pool for datasource 'default'
    [info] application - Shutting down connection pool.

    如果有人有更好的建议,请改进此答案!我已经挣扎了几个月了.

    If somebody has a better suggestion, please improve on this answer! I have been struggling for months.

    这篇关于使用数据库进行测试:“连接过多"的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

    查看全文
    登录 关闭
    扫码关注1秒登录
    发送“验证码”获取 | 15天全站免登陆