Hibernate不会关闭JDBC连接

时间:2013-12-23 16:51:22

标签: hibernate postgresql jsf-2 jdbc

我有一个在tomcat上运行的JSF Web应用程序。 此应用程序使用hibernate连接到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;
}

}

可能导致此问题的原因是什么?

1 个答案:

答案 0 :(得分:0)

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

由于您在未关闭ResultSet的情况下打开了ResultSet,因此可能会出现资源泄漏。

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

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

第四,您创建的永久关闭的预准备语句可能是另一个资源泄漏。