jOOQ fetchResultSet не закрывает соединение с Kotlin - PullRequest
0 голосов
/ 25 марта 2019

Я использую 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 производить объекты с этим отношением (как объяснено на этой ссылке ), но с 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 Ответ

1 голос
/ 25 марта 2019

Код, который создает ресурс, всегда отвечает за его закрытие. И это ты. И ресурс это 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

Обратите внимание, точно так же, как в вашем другом вопросе , я рекомендую вам не звонить use для типа jOOQ DSLContext, поскольку вам это не нужно. В вашем случае DSLContext не является изобретательным, поскольку вы передаете его datasource

О звонке ResultSet.use

Вместо этого вы должны позвонить use на ResultSet, что гарантирует его закрытие после потребления. В этом примере я предполагаю, что ваш вызов toList() будет с нетерпением потреблять весь поток, который оборачивает набор результатов.

Важно помнить, что вы производите ресурс, вызывая jOOQ ResultQuery.fetchResultSet(), и даже если вы передадите его в другую библиотеку, другой библиотеке не требуется закрывать его. Но вы .

...