我担心的是,我在理解Java中的连接池方面存在根本问题。
我正在使用IDBCDataSource作为连接池。 在我的应用程序的入口点,我实例化一个BasicDataSource,例如setMaxActive = 50。该DataSource的实例将被交付给某些业务逻辑使用的各种DAO。
每个DAO调用getConnection(),但没有调用单个close()。我的假设是,在不使用DAO之后,垃圾收集器会关闭连接。
我的问题是我经常耗尽连接(即等待可用连接的代码)。
现在假设我会在每个数据库操作结束时添加一个close()调用。抛出异常会发生什么。我必须捕获DAO中的每个Exception,确保关闭连接然后重新抛出发生的异常!
示例 - 当前方法:
public class MyDAO {
private Connection con;
public MyDAO (DataSource ds) {
con = ds.getConnection();
}
public MyReturnClass execSomeQuery() throws SQLException {
String sql = String.format("SELECT * FROM foo");
PreparedStatement ps = con.prepareStatement(sql);
ResultSet rs = ps.executeQuery();
while (rs.next()) {
…
...
}
return result;
}
}
public class MyAppLogic() {
DataSource ds;
public MyAppLogic(DataSource ds) {
this.ds = ds;
}
public void doSomeStuff() {
MyDAO myDAO = MyDAO(ds);
myDAO.execSomeQuery();
}
}
答案 0 :(得分:2)
您需要close
连接,以便它们在连接池中返回。 GC不会在您的连接上调用关闭!
答案 1 :(得分:2)
您可以创建一个管理连接的包装器或父类,这样您就不必在每个方法中复制逻辑。这是一个例子(注意我实际上没有编译或测试过这个)。
public interface DAOClass {
public void execSomeQuery() throws SQLException;
}
public class MyDAOWrapper {
private DAOClass dao;
private DataSource ds;
public MyDAOWrapper(DataSource ds, DAOClass dao) {
this.dao = dao;
this.ds = ds;
}
public void exec() throws SQLException {
Connection con = ds.getConnection();
try {
dao.execSomeQuery();
}
finally {
con.close();
}
}
}
// usage
public void doSomeStuff() throws SQLException {
MyDAOWrapper dao = new MyDAOWrapper(ds, new MyDAO());
dao.exec();
}
关于错误处理,除非抓住异常,否则不需要重新抛出异常。您的finally
子句应该关闭连接(如果存在),当它退出时,异常将继续传播。
try {
do_something();
}
finally {
cleanup();
// throw is not necessary
}