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,它有自己的连接。
感谢您的回复。
我正在使用 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,它有自己的连接。
感谢您的回复。