使用数据库进行测试:“连接过多" [英] Play tests with database: "Too many connections"
问题描述
为了在 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:
将 jdbc 添加到您的 libraryDependencies,即使 Play-Slick 常见问题解答 告诉您不要这样做:
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屋!