3

我一直在使用 doobie (cats) 从 scalatra 应用程序连接到 postgresql 数据库。最近我注意到该应用程序正在为每个事务创建一个新的连接池。我最终解决了它 - 见下文,但这种方法与 doobie 书的“管理连接”部分中采用的方法完全不同,我希望有人能确认它是否明智或是否有更好的设置方法建立连接池。

这是我最初所拥有的 - 这可以工作,但会在每个连接上创建一个新的连接池:

import com.zaxxer.hikari.HikariDataSource
import doobie.hikari.hikaritransactor.HikariTransactor
import doobie.imports._

val pgTransactor = HikariTransactor[IOLite](
  "org.postgresql.Driver",
  s"jdbc:postgresql://${postgresDBHost}:${postgresDBPort}/${postgresDBName}",
  postgresDBUser,
  postgresDBPassword
)
// every query goes via this function
def doTransaction[A](update: ConnectionIO[A]): Option[A] = {
    val io = for {
      xa <- pgTransactor
      res <- update.transact(xa) ensuring xa.shutdown
    } yield res
    io.unsafePerformIO
}

我最初的假设是ensuring xa.shutdown每个请求都有问题,但是删除它会导致连接很快被用完,直到没有剩余。

这是解决问题的尝试-使我能够删除ensuring xa.shutdown,但仍然导致连接池被反复打开和关闭:

val pgTransactor: HikariTransactor[IOLite] = HikariTransactor[IOLite](
  "org.postgresql.Driver",
  s"jdbc:postgresql://${postgresDBHost}:${postgresDBPort}/${postgresDBName}",
  postgresDBUser,
  postgresDBPassword
).unsafePerformIO

def doTransaction[A](update: ConnectionIO[A]): Option[A] = {
    val io = update.transact(pgTransactor)
    io.unsafePerformIO
}

最后,我通过创建一个HikariDataSource对象然后将其传递给HikariTransactor构造函数来获得所需的行为:

val dataSource = new HikariDataSource()
dataSource.setJdbcUrl(s"jdbc:postgresql://${postgresDBHost}:${postgresDBPort}/${postgresDBName}")
dataSource.setUsername(postgresDBUser)
dataSource.setPassword(postgresDBPassword)

val pgTransactor: HikariTransactor[IOLite] = HikariTransactor[IOLite](dataSource)

def doTransaction[A](update: ConnectionIO[A], operationDescription: String): Option[A] = {
  val io = update.transact(pgTransactor)
  io.unsafePerformIO
}
4

2 回答 2

4

你可以这样做:

val xa = HikariTransactor[IOLite](dataSource).unsafePerformIO

并将其传递给您的存储库。 .transact应用事务边界,如Slick's .transactionally。例如:

def interactWithDb = {
  val q: ConnectionIO[Int] = sql"""..."""
  q.transact(xa).unsafePerformIO
}
于 2017-11-10T13:36:16.727 回答
1

是的,Radu 的回应解决了这个问题。(HikariTransactor底层HikariDataSource真的)有内部状态,所以构造它是一个副作用;并且您想在程序启动时执行一次并根据需要传递它。所以你的解决方案有效,只需注意副作用。

另外,如前所述,我不监控 SO……如果您有问题,请尝试使用 Gitter 频道或打开问题。:-)

于 2017-11-10T16:45:07.180 回答