【问题标题】:Play tests with database: "Too many connections"使用数据库进行测试:“连接太多”
【发布时间】:2017-07-11 03:31:15
【问题描述】:

为了拥有一个可升级的最新数据库,我使用了默认PlaySpec 的扩展,灵感来自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()
  }
}

它在套件启动时应用数据库演变,并在套件结束时恢复它们。然后测试看起来像

class ProjectsSpec extends ResetDbSpec with OneAppPerSuite { ...

在添加更多这样的测试后,我遇到了一个点,即当我单独运行它们时,一些测试成功,但由于以下错误而失败:

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

从上面的代码可以看出,我尝试添加这一行

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

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

注意我使用 Play 2.5.10 和 Slick 3.1。

【问题讨论】:

  • 应用程序是否试图在池中保持比数据库允许打开更多的连接数?
  • @MichaelZajac 我该如何验证?
  • lazy val databaseApi 更改为def databaseApi 有帮助吗?否则,您可以检查playframework.com/documentation/2.5.x/SettingsJDBC 来调整最大池大小。此外,就像@MichaelZajac 所说,您可以检查本地数据库配置以查看它允许多少连接。
  • @Eric def databaseApi 没有帮助。我正在阅读有关如何使用 Slick 设置池大小的信息,但它相当令人困惑 :( 它说要查看一些 JDBC forConfig 东西“但其中大部分都被忽略了”,然后增加线程数或队列大小。@ 987654323@. 我应该选择后者吗?
  • 我在 slick.dbs.default 中设置了numThreads=200queueSize=500,但是没有效果。我也试过maxConnections=5000。编辑:在“slick.dbs.default.db”中,“connectionTimeout”属性有效果(等待更长时间),所以我把所有东西都移到了那里,但它仍然不起作用。

标签: scala testing playframework playframework-2.5 play-slick


【解决方案1】:

我有很多测试(大约 500 个),我没有收到此错误,我与您的代码的唯一区别是我添加了

databaseApi.database("default").getConnection().close()

Play.stop(fakeApplication)

用于集成测试。

如果有任何改变,请告诉我。

【讨论】:

  • 不幸的是它没有:(。只要我在 BeforeAll 或 AfterAll 中调用 databaseApi 就会得到错误(即评估惰性 val)。也许我误解了;我添加了这两行你在afterAll() 中提出建议。我只有大约 120 个测试。也许 MySQL,或者它的 slick 驱动程序,是为了这个。
  • 不,我认为你理解得很好。如果有帮助,我会使用 PostgreSQL,并且我不会更改数据库、slick 或 hikariCP 配置(至少对于测试而言)
【解决方案2】:

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

  1. jdbc 添加到您的 libraryDependencies,即使 Play-Slick FAQ 告诉您不要这样做:

    # build.sbt
    libraryDependencies += jdbc
    

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

  2. 禁用与 play-slick 冲突的 jdbc 模块(来源:this SO answer):

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

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

    slick {
      dbs {
        default {
          driver = "slick.driver.MySQLDriver$"
          db.driver = "com.mysql.jdbc.Driver"
          db.url = "jdbc:mysql://localhost/test"
          db.user = "sa"
          db.password = ""
        }
      }
    }
    
  3. 现在您可以使用 jdbc 中的 play.api.db.Databases 及其方法 withDatabase 来运行演进。

    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)
        }
      }
    
    }
    
  4. 最后,像这样调用需要重置数据库的测试:

    class MySpec extends ResetDbSpec {...}
    

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

[info] 应用程序 - 为数据源“默认”创建池
[info] 应用程序 - 关闭连接池。

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

【讨论】:

    猜你喜欢
    • 2019-09-13
    • 2020-10-10
    • 2018-06-09
    • 2016-01-21
    • 2019-04-18
    • 2015-12-01
    • 1970-01-01
    • 1970-01-01
    • 2019-01-07
    相关资源
    最近更新 更多