【问题标题】:Java Connection Pooling - garbage collection or call close()?Java 连接池 - 垃圾收集或调用 close()?
【发布时间】:2012-12-15 20:22:35
【问题描述】:

我担心我在理解 Java 中的连接池方面存在根本问题。

我使用 IDBCDataSource 作为连接池。 在我的应用程序的入口点,我实例化了一个 BasicDataSource,例如 setMaxActive=50。然后将该 DataSource 的实例传递给某些业务逻辑使用的各种 DAO。

每个 DAO 都调用 getConnection(),但没有调用单个 close()。我的假设是,在不使用 DAO 后,垃圾收集器会关闭连接。

我的问题是我经常用完连接(即代码等待可用连接)。

现在假设我会在每个数据库操作结束时添加一个 close() 调用。抛出的异常会发生什么。我必须捕获 DAO 中的每个异常,确保关闭连接,然后重新抛出发生的异常!

示例 - 当前方法:

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();
     }
}

【问题讨论】:

    标签: java connection-pooling


    【解决方案1】:

    您需要close 连接,以便它们返回连接池。 GC 不会关闭你的连接!

    【讨论】:

    • 那也意味着我需要捕获每个异常,关闭连接然后重新抛出异常?这也意味着每个 DAO 方法都需要单独获取一个连接,而不是为整个 DAO 类分配一个连接。 getConnection() 会导致开销吗?
    • 1) 是的,捕获每个连接 2) 那又怎样?你不会得到任何东西。池将重用连接
    【解决方案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
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2010-12-13
      • 2018-12-30
      • 1970-01-01
      • 2011-11-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多