Мой проект sbt 1.1.6 + playframework 2.7 + play-slick 3.0.0 + mysql-connector-java 5.1.34.
Я запустил приложение по
- 1.
sbt/dist
- 2.
unzip {package}
- 3.
./bin/{project_name} -Dhttp.port=8080
Я обнаружил, что при первом запросе требуется много времени для запроса данных из базы данных.
После того, как я добавил это <logger name="com.zaxxer.hikari" level="DEBUG"/>
для входа в систему, я обнаружил, что Hikari создает соединение с БД после первого выполнения кода db.run()
.
Требуется некоторое время для инициализации соединения с БД, и иногда возникают ошибки, такие как тайм-аут getConnection или тайм-аут ожидания соединения.
Итак, есть ли способ предварительно загрузить создание соединения вместо создания соединения после первого вызова db.run()
.
Я создаю энергичный одноэлементный класс, который выполняет db.run()
до успеха и запускается до запуска приложения.
Например
class InitialDB @Inject() (areaCodeInfoDAO: AreaCodeInfoDAO) (implicit exec: ExecutionContext) {
def init(): Future[String] = {
areaCodeInfoDAO.getProvince("440782")
}
RetryUtil.retry4Future(10)(init())
}
class ApiModule extends AbstractModule {
override def configure(): Unit = {
bind(classOf[InitialDB]).asEagerSingleton()
}
}
Исправлена эта проблема, но не элегантно.
Вот мой пример кода:
import javax.inject._
import scala.concurrent.duration.Duration
import scala.concurrent.{Await, ExecutionContext, Future}
import model.TableQueries
import play.api.db.slick.{DatabaseConfigProvider, HasDatabaseConfigProvider}
import play.api.mvc._
import slick.jdbc.JdbcProfile
import slick.jdbc.MySQLProfile.api._
class HomeController @Inject()(protected val dbConfigProvider: DatabaseConfigProvider)
(cc: ControllerComponents)
(implicit exec: ExecutionContext)
extends AbstractController(cc)
with HasDatabaseConfigProvider[JdbcProfile] {
def index() = Action { implicit request: Request[AnyContent] =>
val query = TableQueries.CODE_NAME_MAPPING
.filter { info =>
info.code === "test"
}
.map(_.name)
.take(1)
val result: Future[String] = db
.run(query.result)
.map(info => if (info.nonEmpty) info.head else "test")
Ok(Await.result(result, Duration.Inf))
}
}
import slick.lifted.TableQuery
object TableQueries {
val CODE_NAME_MAPPING = TableQuery[CodeNameMapping]
}
import slick.jdbc.MySQLProfile.api._
# model
class CodeNameMapping(tag: Tag)
extends Table[(String, String)](tag, "nydd_channel_info") {
def code = column[String]("code", O.PrimaryKey)
def name = column[String]("name")
def * = (code, name)
}
Я добавляю <logger name="com.zaxxer.hikari" level="DEBUG"/>
к logback.xml.
Журнал [debug] находится сразу после того, как я отправляю запрос на запрос базы данных, поэтому я думаю, что Hikari создает соединение с базой данных при первом выполнении кода db.run()
.
[info] play.api.Play - Application started (Prod) (no global state)
[info] p.c.s.AkkaHttpServer - Listening for HTTP on /0:0:0:0:0:0:0:0:9000
[debug] c.z.h.HikariConfig - db - configuration:
[debug] c.z.h.HikariConfig - allowPoolSuspension.............false
[debug] c.z.h.HikariConfig - autoCommit......................true
[debug] c.z.h.HikariConfig - catalog.........................null
[debug] c.z.h.HikariConfig - connectionInitSql...............null