【问题标题】:Hibernate don't close JDBC ConnectionsHibernate 不关闭 JDBC 连接
【发布时间】:2013-12-23 16:51:21
【问题描述】:

我有一个在 tomcat 上运行的 JSF Web 应用程序。 此应用程序使用休眠连接到 Postgres 数据库。

一段时间后,应用程序停止工作,因为它无法打开新连接。 如果在 postgres 中执行以下 sql:

select * from pg_stat_activity

它显示了 100 条记录,并且在“状态”列中显示我空闲。 我追踪了导致这种情况的语句,发现多次执行一条语句会导致这种行为(在我的例子中,它是一个 autoComplete ajax 方法)。 这是声明:

Connection con = ConnectDb.getConnection();
    ArrayList<Cidade> cidades=new ArrayList<Cidade>();
    try{
        PreparedStatement pst=con.prepareStatement("select c.cidCodigo,c.cidNome,e.estCodigo,e.estSigla from cidade c left join estado e on e.estCodigo=c.estCodigo where upper(c.cidNome) like ?");
        pst.setObject(1, s.toUpperCase()+"%");
        ResultSet rs=pst.executeQuery();
        while(rs.next()){
            Cidade c = new Cidade(rs.getInt("cidCodigo"), rs.getString("cidNome"));
            Estado e = new Estado();
            e.setEstCodigo(rs.getInt("estCodigo"));
            e.setEstSigla(rs.getString("estSigla"));
            c.setCidEstado(e);
            cidades.add(c);
        }
    }catch(Exception e){
        e.printStackTrace();
        JsfUtils.showFatalMessage("Erro ao carregar dados: "+e.getLocalizedMessage());
    }finally{
        try{
            con.close();
        }catch(Exception e){
            e.printStackTrace();
        }
    }

这就是我获得连接的方式:

public class ConnectDb {

static EntityManagerFactory emf;

public static EntityManager getEntityManager(){
    return getEntityManagerFactory().createEntityManager();
}

public static EntityManagerFactory getEntityManagerFactory() {
    if(emf==null){
        try {
            emf=Persistence.createEntityManagerFactory("GestaoPU");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    return emf;
}

public static Session getSession(){
    Session session = getEntityManager().unwrap(Session.class);
    session.setFlushMode(FlushMode.AUTO);
    return session;
}

public static Connection getConnection(){
    Object delegate = getEntityManager().getDelegate();
    SessionImpl si=(SessionImpl)delegate;
    Connection con = si.connection();
    try {con.setAutoCommit(false);} catch (SQLException e) {}
    return con;
}

}

什么可能导致这个问题?

【问题讨论】:

  • 也许您需要保留对 EntityManager 的引用并在其上调用 close()。只是猜测。
  • 我注意到在使用 Session/EntityManager 时也会出现问题,所以我不认为是这种情况......

标签: hibernate postgresql jsf-2 jdbc


【解决方案1】:

Connection.close() 并不总是在物理上“关闭”连接。通常在生产代码中,连接被包装在由连接池生成的代理中。代理中的 close 方法可能不会关闭连接,而是将其返回到池中。

由于你打开了一个 ResultSet 而没有关闭它,你可能会发生资源泄漏。

接下来,既然你已经从hibernate“借用”了连接,你不应该明确地将连接返回到池中(或者可以说是在hibernate背后关闭它)。

第三,由于您对从 getDelegate() 返回的会话的唯一引用是在 ConnectDb.getConnection() 中,因此不太清楚该会话会发生什么。这取决于调用它的上下文。它可能立即有资格进行垃圾收集,或者它可能由本地线程持有。如果它实际上是立即 gc'd 那么休眠会话将在您的代码有机会使用它之前将其连接返回到池。这可能会导致不可预知的行为或难以追踪错误。

第四,你创建的永远不会关闭的prepared statement可能是另一个资源泄漏。

【讨论】:

  • 首先,连接的关闭不会自动关闭它的语句和结果集吗?其次,我从未在应用程序上定义连接池,是否有使用休眠的“默认”连接池?四、和第一一样,PreparedStatement的关闭不会自动关闭与之关联的ResultSets吗?
  • 关闭属于连接池的连接并不一定会导致关闭其语句和结果集。它只返回到池的连接。这可能取决于实现,因为连接池实现可以提供一个代理或连接,它本质上跟踪在连接的活动周期期间创建的资源,因此在连接返回池时关闭这些资源。没有实现我知道它会在关闭时关闭语句生成的结果集。
  • 这篇链接文章的作者提供了一些关于如何正确关闭 jdbc 资源的更多见解。 blog.shinetech.com/2007/08/04/… 不过在我看来,他的异常处理是有缺陷的,因为任何 close 语句中的异常都会抑制结果集的迭代和处理产生的任何异常。
猜你喜欢
  • 1970-01-01
  • 2012-03-29
  • 1970-01-01
  • 2012-11-03
  • 1970-01-01
  • 2014-09-11
  • 2012-08-28
  • 1970-01-01
  • 2014-06-22
相关资源
最近更新 更多