我将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生成具有这种关系的对象(如{{ 3}}),但使用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()...
}
}
}
这是我应该使用的最后一种方法吗?
答案 0 :(得分:1)
产生资源的代码总是负责关闭它。那就是你。资源是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
请注意,就像in your other question一样,我建议您不要调用jOOQ的use
类型的DSLContext
,因为您不需要它。在您的情况下,DSLContext
在您传递datasource
ResultSet.use
相反,您应该在use
上调用ResultSet
,以确保使用后将其关闭。在此示例中,我假设您对toList()
的调用将急切地消耗包装结果集的整个流。
这里要记住的重要一点是,您是通过调用jOOQ的ResultQuery.fetchResultSet()
来产生资源的,即使将其传递给另一个库,也不需要其他库来关闭它。但是您是。