首页 文章

JDBC MySql连接池实践,以避免耗尽连接池

提问于
浏览
10

我在GlassFish上有一个Java-JSF Web应用程序,我想在其中使用连接池 . 因此,我创建了一个 application 范围的bean,为其他bean的 Connection 实例提供服务:

public class DatabaseBean {

    private DataSource myDataSource;

    public DatabaseBean() {
        try {
            Context ctx = new InitialContext();
            ecwinsDataSource = (DataSource) ctx.lookup("jdbc/myDataSource");
        } catch (NamingException ex) {
            ex.printStackTrace();
        }
    }

    public Connection getConnection() throws ClassNotFoundException, SQLException, InstantiationException, IllegalAccessException {
        Connection connection = myDataSource.getConnection();
        System.out.println("Succesfully connected: " + connection);
        //Sample: Succesfully connected: com.sun.gjc.spi.jdbc40.ConnectionHolder40@7fb213a5
        return connection;
    }
}

这样连接池的填充速度非常快;在通过“db-related”视图进行一些导航后,应用程序将停止并显示以下内容:

RAR5117:无法从连接池[mysql_testPool]获取/创建连接 . 原因:正在使用的连接等于max-pool-size和expired max-wait-time . 无法分配更多连接 . RAR5114:分配连接时出错:[分配连接时出错 . 原因:正在使用的连接等于max-pool-size和expired max-wait-time . 无法分配更多连接 . ] java.sql.SQLException:分配连接时出错 . 原因:正在使用的连接等于max-pool-size和expired max-wait-time . 无法分配更多连接 .

我正在关闭每种方法中的连接和其他资源 . 应用程序通过独立连接运行一切正常 .

我究竟做错了什么?任何提示或建议将不胜感激 .

2 回答

  • 0

    如果您需要JDBC连接池,为什么不依赖已有的连接池? AFAIK,JDBC连接池在这些Java应用程序服务器中被认为或多或少是标准功能,而IMO,如果您只是对创建应用程序感兴趣,则不应该自己构建它 .

    这是一个可以帮助您入门的链接:http://weblogs.java.net/blog/2007/09/12/totd-9-using-jdbc-connection-pooljndi-name-glassfish-rails-application

    您可能应该做的是找出如何让您的应用程序使用jndi从池中获取连接 .

  • 20

    该异常表示泄漏数据库连接的应用程序代码的典型情况 . 您需要确保在根据普通JDBC习惯用法的同一方法块中的try-with-resources块中获取所有这些( ConnectionStatement and ResultSetand .

    public void create(Entity entity) throws SQLException {
        try (
            Connection connection = dataSource.getConnection();
            PreparedStatement statement = connection.prepareStatement(SQL_CREATE);
        ) { 
            statement.setSomeObject(1, entity.getSomeProperty());
            // ...
            statement.executeUpdate();
        }
    }
    

    或者当你没有使用Java 7时,在 try-finally 块中 . 在 finally 关闭它们将保证在例外情况下它们也会关闭 .

    public void create(Entity entity) throws SQLException {
        Connection connection = null;
        PreparedStatement statement = null;
    
        try { 
            connection = dataSource.getConnection();
            statement = connection.prepareStatement(SQL_CREATE);
            statement.setSomeObject(1, entity.getSomeProperty());
            // ...
            statement.executeUpdate();
        } finally {
            if (statement != null) try { statement.close(); } catch (SQLException logOrIgnore) {}
            if (connection != null) try { connection.close(); } catch (SQLException logOrIgnore) {}
        }
    }
    

    是的,即使使用连接池,您仍需要自己关闭连接 . 在初学者中,他们认为它会自动处理结束是一个常见的错误 . 这是 not true . 连接池返回一个包装的连接,它在close()中执行类似下面的操作:

    public void close() throws SQLException {
        if (this.connection is still eligible for reuse) {
            do not close this.connection, but just return it to pool for reuse;
        } else {
            actually invoke this.connection.close();
        }
    }
    

    不关闭它们会导致连接没有被释放回池中以便重复使用,因此它将一次又一次地获取一个新连接,直到数据库用尽连接,这将导致应用程序崩溃 .

    另见:

相关问题