jOOQ fetchResultSet 没有关闭与 Kotlin 的连接
jOOQ fetchResultSet not closing connection with Kotlin
我将 Kotlin 与 HikariCP 和 jOOQ 结合使用来查询我的数据库。我开始意识到此代码按预期工作,获取行并随后关闭连接:
class CountriesService(private val datasource: DataSource) {
private val countries = Countries()
fun getCountries(): List<Country> {
DSL.using(datasource, SQLDialect.POSTGRES_10)
.use { ctx ->
return ctx.select(...)
.from(...)
.orderBy(...)
.fetch(Country.mapper) // val mapper: (CountriesRecord) -> Country = {...}
}
}
}
在向 Country
添加多对多关系后,此映射器不再适用,因此我想获得一个 ResultSet
并使用 SimpleFlatMapper 生成具有此关系的对象(如上所述this link),但是对于 fetchResultSet()
,连接永远不会关闭并且池干涸:
class CountriesService(private val datasource: DataSource) {
private val countries = Countries()
fun getCountries(): List<Country> {
DSL.using(datasource, SQLDialect.POSTGRES_10)
.use { ctx ->
val rs = ctx.select(...)
.from(...)
.orderBy(...)
.fetchResultSet()
return Country.mapper.stream(rs).toList() // val mapper = JdbcMapperFactory.newInstance()...
}
}
}
我看到 AbstractResultQuery#fetchResultSet()
正在委托给 fetchLazy()
方法,所以不确定它是否与此有关。
如果我自己获得连接而不是将其委托给 DSLContext
,那么它将起作用:
class CountriesService(private val datasource: DataSource) {
private val countries = Countries()
fun getCountries(): List<Country> {
val conn = datasource.connection
conn.use {
val rs = DSL.using(it, SQLDialect.POSTGRES_10)
.select(...)
.from(...)
.orderBy(...)
.fetchResultSet()
return Country.mapper.stream(rs).toList() // val mapper = JdbcMapperFactory.newInstance()...
}
}
}
我应该使用最后一种方法吗?
产生资源的代码总是负责关闭它。那就是你。资源是 ResultSet
。您的代码应该如下所示:
class CountriesService(private val datasource: DataSource) {
private val countries = Countries()
fun getCountries(): List<Country> {
val ctx = DSL.using(datasource, SQLDialect.POSTGRES_10)
return
ctx.select(...)
.from(...)
.orderBy(...)
.fetchResultSet()
.use {
return Country.mapper.stream(it).toList()
}
}
}
关于调用DSLContext.use
注意,就像 一样,我建议您不要在 jOOQ 的 DSLContext
类型上调用 use
,因为您不需要它。在您的情况下, DSLContext
不是足智多谋,因为您将其传递给 datasource
关于调用ResultSet.use
相反,您应该在 ResultSet
上调用 use
,这保证它在使用后关闭。在此示例中,我假设您对 toList()
的调用将急切地使用包装结果集的整个流。
这里要记住的重要一点是 你 通过调用 jOOQ 的 ResultQuery.fetchResultSet()
来生成资源,即使你将它传递给另一个库,另一个库也是不需要关闭它。但是你是。
我将 Kotlin 与 HikariCP 和 jOOQ 结合使用来查询我的数据库。我开始意识到此代码按预期工作,获取行并随后关闭连接:
class CountriesService(private val datasource: DataSource) {
private val countries = Countries()
fun getCountries(): List<Country> {
DSL.using(datasource, SQLDialect.POSTGRES_10)
.use { ctx ->
return ctx.select(...)
.from(...)
.orderBy(...)
.fetch(Country.mapper) // val mapper: (CountriesRecord) -> Country = {...}
}
}
}
在向 Country
添加多对多关系后,此映射器不再适用,因此我想获得一个 ResultSet
并使用 SimpleFlatMapper 生成具有此关系的对象(如上所述this link),但是对于 fetchResultSet()
,连接永远不会关闭并且池干涸:
class CountriesService(private val datasource: DataSource) {
private val countries = Countries()
fun getCountries(): List<Country> {
DSL.using(datasource, SQLDialect.POSTGRES_10)
.use { ctx ->
val rs = ctx.select(...)
.from(...)
.orderBy(...)
.fetchResultSet()
return Country.mapper.stream(rs).toList() // val mapper = JdbcMapperFactory.newInstance()...
}
}
}
我看到 AbstractResultQuery#fetchResultSet()
正在委托给 fetchLazy()
方法,所以不确定它是否与此有关。
如果我自己获得连接而不是将其委托给 DSLContext
,那么它将起作用:
class CountriesService(private val datasource: DataSource) {
private val countries = Countries()
fun getCountries(): List<Country> {
val conn = datasource.connection
conn.use {
val rs = DSL.using(it, SQLDialect.POSTGRES_10)
.select(...)
.from(...)
.orderBy(...)
.fetchResultSet()
return Country.mapper.stream(rs).toList() // val mapper = JdbcMapperFactory.newInstance()...
}
}
}
我应该使用最后一种方法吗?
产生资源的代码总是负责关闭它。那就是你。资源是 ResultSet
。您的代码应该如下所示:
class CountriesService(private val datasource: DataSource) {
private val countries = Countries()
fun getCountries(): List<Country> {
val ctx = DSL.using(datasource, SQLDialect.POSTGRES_10)
return
ctx.select(...)
.from(...)
.orderBy(...)
.fetchResultSet()
.use {
return Country.mapper.stream(it).toList()
}
}
}
关于调用DSLContext.use
注意,就像 DSLContext
类型上调用 use
,因为您不需要它。在您的情况下, DSLContext
不是足智多谋,因为您将其传递给 datasource
关于调用ResultSet.use
相反,您应该在 ResultSet
上调用 use
,这保证它在使用后关闭。在此示例中,我假设您对 toList()
的调用将急切地使用包装结果集的整个流。
这里要记住的重要一点是 你 通过调用 jOOQ 的 ResultQuery.fetchResultSet()
来生成资源,即使你将它传递给另一个库,另一个库也是不需要关闭它。但是你是。