HikariCP not closing connections on close() (Connection Leak)

10,210

You forgot to close also PreparedStatement

try {
       if (preparedStatement != null) {
            preparedStatement.close();
       }
       if (dbConnection != null) {
            dbConnection.close();
       }

Releases this Statement object's database and JDBC resources immediately instead of waiting for this to happen when it is automatically closed. It is generally good practice to release resources as soon as you are finished with them to avoid tying up database resources.

Share:
10,210
Nikita Kalugin
Author by

Nikita Kalugin

Updated on June 04, 2022

Comments

  • Nikita Kalugin
    Nikita Kalugin almost 2 years

    I'm using HikariCP 3.3.1 and PostgreSQL. But I've a problem with closing my connections, in Hikari config I set maximum pool size to 15 and minimum idle connection to 5, but after a few minutes of work with database I've found out connections don't closes, they stack more and more (almost 100 Idle connections right now). enter image description here

    My Connector class:

    Connector.java

    public class Connector implements IConnector {
    private static HikariConfig config = new HikariConfig();
    private static HikariDataSource ds;
    
    static {
        config.setDriverClassName(org.postgresql.Driver.class.getName());
        config.setJdbcUrl("jdbc:postgresql://localhost:5432/vskDB");
        config.setUsername("postgres");
        config.setPassword("root");
        config.setMinimumIdle(5);
        config.setMaximumPoolSize(15);
        config.setConnectionTimeout(20000);
        config.setIdleTimeout(300000);
        ds = new HikariDataSource(config);
    }
    
    public Connection getConnection() {
        log.info("getConnection() invoked");
        try {
            return ds.getConnection();
        } catch (SQLException e) {
            log.error("Can't get connection from DataSource.");
            log.error(e.getMessage());
            System.out.println(e.getMessage());
        }
        return null;
    }
    
    Connector() {
    }
    }
    

    And here's my DAO class (simplified): UserDAO.java

    public class UserDatabaseDAO implements UserDAO {
        private Connector connector = new Connector();
        private Connection dbConnection;
    
        @Override
        public void removeUser(Long id) {
            try {
                dbConnection = connector.getConnection();
                if (dbConnection == null)
                    throw new ConnectException();
    
                PreparedStatement preparedStatement = dbConnection.prepareStatement("DELETE FROM users WHERE user_id = ?");
                preparedStatement.setLong(1, id);
                preparedStatement.execute();
    
            } catch (SQLException | ConnectException e) {
                log.error("Can't remove user from database");
                log.error(e.getMessage());
                System.out.print(e.getMessage());
            } finally {
                try {
                    dbConnection.close();
                } catch (SQLException e) {
                    log.error("Can't close connection");
                    log.error(e.getMessage());
                    System.out.print(e.getMessage());
                }
            }
        }
    }
    

    Here I've found an issue with some facts about Hikari:
    You must call close() on the connection instance that HikariCP gives you

    Maybe my dbConnection.close() wont work because it's just a copy of Connection which Hikari gives me in getConnection() method.