【问题标题】:Tomcat PooledConnections Using MYSQLTomcat PooledConnections 使用 MYSQL
【发布时间】:2016-04-11 02:09:11
【问题描述】:

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

数据源拒绝建立连接,来自服务器的消息:“连接太多”

我对池的理解是,它将创建配置的最大连接数,然后开始重用这些连接,并根据需要提供它们。我最初怀疑代码中存在泄漏,但经过审查后我不确定问题可能是什么。当 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 进行连接。

非常感谢任何帮助。

【问题讨论】:

  • 你在哪里打电话给createConnection()getPooledConnection() 的代码在哪里?你从哪里打电话给executeStatement()
  • 感谢 Gergely 的回复。我添加了方法 getPooledConnection() 和 executeStatement();
  • 感谢 Gergely 的评论。我添加了缺少的方法。我正在从 DatabaseManager 类的构造函数中调用 createConnection。

标签: java mysql tomcat jdbc connection-pooling


【解决方案1】:

您不应该创建自己的 Datasource 对象。 Tomcat 为您完成。查看sample code in its documentation 并关注它。

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

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

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

【讨论】:

  • 我求助于创建自己的数据源,因为创建 context.xml 文件的 JNDI 路径不适合我。我正在从 DatabaseManager 类构造函数中调用 createConnection。
【解决方案2】:

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

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

感谢您的回复。

【讨论】:

    猜你喜欢
    • 2011-01-22
    • 2014-06-27
    • 2019-05-11
    • 2011-07-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-06-15
    相关资源
    最近更新 更多