我正在使用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
请注意,就像in your other question一样,我建议你不要在jOOQ的use
类型上调用DSLContext
,因为你不需要它。在你的情况下,DSLContext
没有足够的资源,因为你传递了datasource
ResultSet.use
相反,你应该在use
上调用ResultSet
,这可以保证它在消费后关闭。在这个例子中,我假设您对toList()
的调用将急切地消耗包装结果集的整个流。
这里要记住的重要一点是你通过调用jOOQ的ResultQuery.fetchResultSet()
来生成资源,即使你将它传递给另一个库,也不需要关闭它。但你是。