jOOQ fetchResultSet没有关闭与Kotlin的连接

问题描述 投票:0回答:1

我正在使用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()...
        }
    }
}

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

kotlin jooq hikaricp
1个回答
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()
            }
    }
}

About calling DSLContext.use

请注意,就像in your other question一样,我建议你不要在jOOQ的use类型上调用DSLContext,因为你不需要它。在你的情况下,DSLContext没有足够的资源,因为你传递了datasource

About calling ResultSet.use

相反,你应该在use上调用ResultSet,这可以保证它在消费后关闭。在这个例子中,我假设您对toList()的调用将急切地消耗包装结果集的整个流。

这里要记住的重要一点是你通过调用jOOQ的ResultQuery.fetchResultSet()来生成资源,即使你将它传递给另一个库,也不需要关闭它。但你是。

© www.soinside.com 2019 - 2024. All rights reserved.