Ivar Reukers
Ivar Reukers

Reputation: 7719

Kotliquery doesn't close postgresql connections

I'm using Kotlin with the kotliquery jdbc framework

Just ran into a problem. I'm using a remote PostgreSQL database. After a bit of calling the database I get the following error Failure: too many clients already. Which is caused by 100 connections being idle.

I'm trying to create 1 point where I have to do the config. This is what I call my BaseDAO. The relevant code for that class looks like this:

import com.zaxxer.hikari.HikariConfig
import com.zaxxer.hikari.HikariDataSource
import kotliquery.Session
import kotliquery.sessionOf
import javax.sql.DataSource

class BaseDAO {
    companion object {
        var url: String = "jdbc:postgresql://server.local:5432/myDatabase"
        var user: String = "postgres"
        var pass: String = "postgres"

        val config: HikariConfig = HikariConfig()

        private fun dataSource(): DataSource
        {
            var hikariConfig: HikariConfig =  HikariConfig();
            hikariConfig.setDriverClassName("org.postgresql.Driver");
            hikariConfig.setJdbcUrl(url);
            hikariConfig.setUsername(user);
            hikariConfig.setPassword(pass);

            hikariConfig.setMaximumPoolSize(5);
            hikariConfig.setConnectionTestQuery("SELECT 1");
            hikariConfig.setPoolName("springHikariCP");

            hikariConfig.addDataSourceProperty("dataSource.cachePrepStmts", "true");
            hikariConfig.addDataSourceProperty("dataSource.prepStmtCacheSize", "250");
            hikariConfig.addDataSourceProperty("dataSource.prepStmtCacheSqlLimit", "2048");
            hikariConfig.addDataSourceProperty("dataSource.useServerPrepStmts", "true");

            var dataSource: HikariDataSource  = HikariDataSource(hikariConfig);

            return dataSource;
        }

        @JvmStatic fun getSession(): Session {
            return sessionOf(dataSource())
        }
    }

}

And one of my DAO's:

class UserDAO {

    val toUser: (Row) -> User = { row ->
        User(
                row.int("id"),
                row.string("username"),
                row.string("usertype")
        )
    }

    fun getAllUsers(): List<User> {
        var returnedList: List<User> = arrayOf<User>().toList()
        using(BaseDAO.getSession()) { session ->

            val allUsersQuery = queryOf("select * from quintor_user").map(toUser).asList
            returnedList = session.run(allUsersQuery)
            session.connection.close() 
            session.close()
        }

        return returnedList
    }
}

After looking into Kotliquery's source code I realized the session.connection.close() and session.close wouldn't even be neccessary when using using (since it closes a closable which the retrieved session is.) but without them I got the same error. (had to restart postgresql database -- 100 idle connections).

I was wondering if there is an error in my code or if this is an error in Kotliquery?

(also submitted github issue #6 but figured the community might be bigger than 24 people

Upvotes: 1

Views: 534

Answers (1)

miensol
miensol

Reputation: 41648

It seems that each call to BaseDAO.getSession() creates new HikariDataSource. This means that every Session has effectively it's own database connection pool. To resolve that you need to maintain instance of HikariDataSource differently i.e.:

class BaseDAO {
    companion object {
        ...
        private val dataSource by lazy {
            var hikariConfig: HikariConfig =  HikariConfig();
            ...
            var dataSource: HikariDataSource  = HikariDataSource(hikariConfig);

            dataSource;
        }

        @JvmStatic fun getSession(): Session {
            return sessionOf(dataSource)
        }
    }

}

Upvotes: 1

Related Questions