我一直在使用doobie(cats)从scalatra应用程序连接到postgresql数据库。最近我注意到应用程序正在为每个事务创建一个新的连接池。我最终解决了这个问题 - 见下文,但这种方法与'managing connections' section of the book of 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
}
答案 0 :(得分:4)
您可以这样做:
val xa = HikariTransactor[IOLite](dataSource).unsafePerformIO
并将其传递给您的存储库。
.transact
应用了事务边界,例如Slick
的{{1}}。
E.g:
.transactionally
答案 1 :(得分:1)
是的,Radu的回应解决了这个问题。 HikariTransactor
(真正的基础HikariDataSource
)具有内部状态,因此构建它是一种副作用;并且您希望在程序启动时执行一次并根据需要传递它。所以你的解决方案有效,只需注意副作用。
另外,如上所述,我不会监控SO ...如果您有疑问,请尝试使用Gitter频道或打开问题。 :-)