我有一个在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;
}
}
可能导致此问题的原因是什么?
答案 0 :(得分:0)
Connection.close()并不总是在物理上“关闭”连接。通常在生产代码中,连接包装在由连接池生成的代理中。代理中的close方法可能不会关闭连接,而是将其返回到池中。
由于您在未关闭ResultSet的情况下打开了ResultSet,因此可能会出现资源泄漏。
接下来,既然你已经“借用”了来自hibernate的连接,你就不应该明确地将连接返回到池中(或者在hibernate的后面关闭它可以这么说)。
第三,由于您对getDelegate()返回的会话的唯一引用是在ConnectDb.getConnection()中,因此有些不清楚该会话会发生什么。这取决于调用它的上下文。它可能立即有资格进行垃圾收集,也可能由本地线程持有。如果它实际上是立即gc'd那么hibernate会话将在你的代码有机会使用它之前返回它与池的连接。这可能导致不可预测的行为或难以追踪错误。
第四,您创建的永久关闭的预准备语句可能是另一个资源泄漏。