jOOQ fetch vs fetchResultSet 并在 Kotlin 中关闭连接

jOOQ fetch vs fetchResultSet and close connection in Kotlin

我将 Kotlin 与 HikariCP 和 jOOQ 结合使用来查询我的数据库。我开始意识到此代码按预期工作,获取行并随后关闭连接:

class CountriesService(private val datasource: DataSource) {

    private val countries = Countries()

    fun getCountries(): List<String> {
        DSL.using(datasource, SQLDialect.POSTGRES_10)
            .use { ctx ->
                ctx.select(countries.CO_NAME)
                    .from(countries)
                    .orderBy(countries.CO_NAME)
                    .fetch()
                return emptyList()
            }
    }
}

而如果我使用 fetchResultSet(),则连接永远不会关闭并且池会干涸:

class CountriesService(private val datasource: DataSource) {

    private val countries = Countries()

    fun getCountries(): List<String> {
        DSL.using(datasource, SQLDialect.POSTGRES_10)
            .use { ctx ->
                ctx.select(countries.CO_NAME)
                    .from(countries)
                    .orderBy(countries.CO_NAME)
                    .fetchResultSet()
                return emptyList()
            }
    }
}

我看到 AbstractResultQuery#fetchResultSet() 正在委托给 fetchLazy() 方法,所以不确定它是否与此有关。

如果我自己获得连接而不是将其委托给 DSLContext,那么它会起作用:

class CountriesService(private val datasource: DataSource) {

    private val countries = Countries()

    fun getCountries(): List<String> {
        val conn = datasource.connection
        conn.use {
            DSL.using(it, SQLDialect.POSTGRES_10)
                .select(countries.CO_NAME)
                .from(countries)
                .orderBy(countries.CO_NAME)
                .fetchResultSet()
            return emptyList()
        }
    }
}

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

它完全按照 Javadoc 中指定的方式工作:

This is the same as calling fetchLazy().resultSet() and will return a ResultSet wrapping the JDBC driver's ResultSet. Closing this ResultSet may close the producing Statement or PreparedStatement, depending on your setting for keepStatement(boolean).

此方法的要点是您想要使用 JDBC 结果集而不是让 jOOQ 为您使用它。因此,您负责资源管理。

鉴于您的示例代码,您绝对不应调用此方法,而应调用 fetch()。例如:

class CountriesService(private val datasource: DataSource) {

    private val countries = Countries()

    fun getCountries(): List<String> {
        return
        DSL.using(datasource, SQLDialect.POSTGRES_10)
           .select(countries.CO_NAME)
           .from(countries)
           .orderBy(countries.CO_NAME)
           .fetch(countries.CO_NAME)
    }
}

注意,您不需要在 DSLContext 上调用 use() 方法。虽然 DSLContext 扩展了 AutoCloseable,但仅当您的 DSLContext 管理基础 JDBC 连接(即创建它时)时才需要这样做。在您的情况下,当您将数据源传递给 DSL.using() 时,您不必关闭 DSLContext.