jOOQ fetchResultSet没有关闭与Kotlin的连接

时间:2019-03-25 10:49:36

标签: kotlin jooq hikaricp

我将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()...
        }
    }
}

这是我应该使用的最后一种方法吗?

1 个答案:

答案 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()来产生资源的,即使将其传递给另一个库,也不需要其他库来关闭它。但是是。