JDBC MySql 连接池实践避免连接池耗尽
Posted
技术标签:
【中文标题】JDBC MySql 连接池实践避免连接池耗尽【英文标题】:JDBC MySql connection pooling practices to avoid exhausted connection pool 【发布时间】:2011-01-19 18:28:33 【问题描述】:我在 GlassFish 上有一个 Java-JSF Web 应用程序,我想在其中使用连接池。因此,我创建了一个 application
作用域 bean,它与 Connection
实例一起为其他 bean 服务:
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 和过期的 max-wait-time。无法分配更多连接。 RAR5114:分配连接时出错:[分配连接时出错。原因:使用中的连接等于 max-pool-size 和过期的 max-wait-time。无法分配更多连接。] java.sql.SQLException:分配连接时出错。原因:使用中的连接等于 max-pool-size 和过期的 max-wait-time。无法分配更多连接。
我正在关闭所有方法中的连接和其他资源。应用程序通过独立连接运行一切正常。
我做错了什么?任何提示或建议将不胜感激。
【问题讨论】:
【参考方案1】:该异常表示应用程序代码泄漏数据库连接的典型案例。您需要确保以完全相同的方法在try-with-resources
块中获取并关闭所有它们(Connection
、Statement
和 ResultSet
)按照正常的 JDBC 习惯进行阻塞。
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)
是的,即使使用连接池,您仍然需要自己关闭连接。初学者中的一个常见错误是他们认为它会自动处理关闭。这不正确。连接池即返回一个包装的连接,它在 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();
不关闭它们会导致连接不会被释放回池以供重用,因此它将一次又一次地获取新的连接,直到数据库用完连接,这将导致您的应用程序崩溃。
另见:
How often should Connection, Statement and ResultSet be closed in JDBC? Is it safe to use a static java.sql.Connection instance in a multithreaded system? Closing JDBC Connections in Pool【讨论】:
感谢您的详尽回答,这真的很有帮助!我用 app-modifications 编辑了我的评论。 再次感谢您提供的重要信息!【参考方案2】:如果您需要 JDBC 连接池,为什么不依赖现有的呢? AFAIK,JDBC 连接池或多或少被认为是这些 Java 应用程序服务器中的标准功能,而 IMO,如果您只是对创建应用程序感兴趣,您不应该自己构建它。
这是一个可以帮助您入门的链接: http://weblogs.java.net/blog/2007/09/12/totd-9-using-jdbc-connection-pooljndi-name-glassfish-rails-application
您可能应该做的是找出如何让您的应用程序使用 jndi 从池中获取连接。
【讨论】:
他已经这样做了?他已经在 appserver 中配置了一个连接池数据源。他只是没有按照异常正确关闭资源。以上是关于JDBC MySql 连接池实践避免连接池耗尽的主要内容,如果未能解决你的问题,请参考以下文章
在 Hibernate/C3P0 中处理连接池耗尽并避免死锁