Tomcat 使用 MYSQL 的 PooledConnections

Tomcat PooledConnections Using MYSQL

我正在使用 jersey 2.0 创建一个 RESTful 网络服务,它使用 Tomcat 连接池连接到 mysql 数据库。我遇到 运行 一个问题,当我将 maxActive 连接数设置为大于 1 时,我在大约 15 个后续请求调用后收到以下错误消息。

数据源拒绝建立连接,来自服务器的消息:"Too many connections"

我对池化的理解是它会创建配置的最大连接数,然后开始重用这些连接,根据需要提供它们。我最初怀疑代码中存在泄漏,但经过审查后我不确定问题出在哪里。当 maxActive 设置为 1 时,不会出现此问题。

这是我的代码。

public DatabaseManager(Properties connProps){
    this.connProps = connProps;
    this.createConnection();
    this.createTableRepository();
}

public void createConnection()
{
    try {
        Context context = new InitialContext();
        Context envCtx = (Context)context.lookup("java:comp/env");
        this.dataSource = new DataSource();
        PoolProperties props = new PoolProperties();
        props.setUrl(this.connProps.getProperty("url"));
        props.setUsername(this.connProps.getProperty("username"));
        props.setPassword(this.connProps.getProperty("password"));
        props.setDriverClassName(this.connProps.getProperty("driverClassName"));
        props.setMaxActive(Integer.parseInt(this.connProps.getProperty("maxActive")));
        this.dataSource.setPoolProperties(props);
    } catch (NamingException e) {

    }
}

private void createTableRepository()
{
    this.tableRepository = new TableRepository();
    Connection connection = null;
    ResultSet rs = null;
    try {
        connection = getPooledConnection();
        DatabaseMetaData dbMeta = (DatabaseMetaData)connection.getMetaData();
        rs = dbMeta.getTables(null, null, "%s", null);
        while(rs.next()){
            String tableName = rs.getString(3);
            TableMeta table = new TableMeta(tableName);
            ResultSet columns = dbMeta.getColumns(null, null, tableName, null);
            while(columns.next()){
                table.addColumn(columns.getString(4));
            }
            this.tableRepository.addTable(tableName, table);
        }
    } catch (SQLException e) {
        e.printStackTrace();
    }
    finally{
        if(rs != null){
            try{
                rs.close();
                rs = null;
                }
            catch(SQLException e){}}
        if(connection != null){
            try{
                connection.close();
                connection = null;
                }
            catch(SQLException e){}}
    }
}

private void executeStatement(IDBQuery dbQuery)
{
    Connection connection = null;
    PreparedStatement statement = null;
    ResultSet rs = null;
    int rows = 0;
    try {
        connection = this.dataSource.getConnection();
        statement = connection.prepareStatement(dbQuery.toString());
        if(dbQuery instanceof DBQuerySelect){
            rs = statement.executeQuery();
            if(rs != null){
                dbQuery.populateQueryResuls(rs);
            }
        }
        else {
            rows = statement.executeUpdate();
            if(rows > 0){
                dbQuery.populateQueryResults(rows);
            }
        }
        if(rs != null){
            rs.close();
        }
        if(statement != null){
            statement.close();
        }
        if(connection != null){
            connection.close();
        }
    } catch (SQLException e) {
        e.printStackTrace();
    }
    finally {
        if(rs != null){try{rs.close(); rs = null;}catch(SQLException e){}}
        if(statement != null){try{statement.close(); statement = null;}catch(SQLException e){}}
        if(connection != null){try{connection.close(); connection = null;}catch(SQLException e){}}
    }
}

public Connection getPooledConnection(){
    Connection con = null;
    try {
        con = this.dataSource.getConnection();
    } catch (SQLException e) {
        e.printStackTrace();
    }
    return con;
}

我用两种方法调用连接,每一种都在 finally 块中关闭 ResultSet、Statement 和 Connection 以确保它们已关闭。我不知道是什么导致连接达到最大值。

我正在使用 mysql-connector-java-5.1.38.jar 进行连接。

非常感谢任何帮助。

您不应该创建自己的数据源对象。 Tomcat 为你做。检查 sample code in its documentation 并遵循它。

此外,如果您创建数据源对象(在您的方法 createConnection() 中)遇到任何问题,您将留下一个 half-configured 数据源。

最后:确保只调用一次 createConnection 方法。

如果这一切都没有帮助:向我们展示您的 Tomcat-Datasource 配置(例如 xml)

@Olaf Kock 的回答让我调查了位于 META-INF 文件夹下的原始 context.xml 文件。最初,我使用 Tomcat 通过配置 context.xml 文件来创建我的 JNDI 数据源。这几天前就停止工作了,所以我求助于自己创建数据源。

看完 Olaf 的评论后,我重新审视了我的 context.xml 文件,发现名称已更改为 content.xml!这导致出现错误消息 org.apache.tomcat.dbcp.dbcp.SQLNestedException:无法为连接 URL 'null' 创建 class 的 JDBC 驱动程序几天前我无法理解。现在我回到使用 JNDI 创建我的数据源,我不再收到 max-connections 错误消息。我仍然不确定为什么创建自己的 DataSoure 会导致问题,因为我根据 tomcat 文档关闭了所有连接。我能得出的唯一结论是,通过在我的 DatabaseManager class 的构造中创建我自己的 DataSource,我每次都创建了一个单独的 DataSource,它有自己的连接。

感谢您的回复。