【问题标题】:jOOQ fetchResultSet not closing connection with KotlinjOOQ fetchResultSet 未关闭与 Kotlin 的连接
【发布时间】:2019-08-15 14:15:38
【问题描述】:

我正在使用 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】:

    产生资源的代码总是负责关闭它。那就是你。资源是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的DSLContext类型上调用use,因为你不需要它。在您的情况下,DSLContext 并不足智多谋,因为您将其传递给 datasource

    关于拨打ResultSet.use

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

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

    【讨论】:

      猜你喜欢
      • 2019-08-15
      • 1970-01-01
      • 2015-06-08
      • 2021-04-14
      • 1970-01-01
      • 2011-05-04
      • 2016-08-13
      • 2014-02-19
      • 2017-09-13
      相关资源
      最近更新 更多