Hibernate、C3P0、postgres、Tomcat连接在事务中处于空闲状态
我们有一个使用Hibernate连接到postgre数据库的应用程序。我们使用C3P0作为连接池 persistence.xml: org.hibernate.ejb.HibernatePersistence ---类别--Hibernate、C3P0、postgres、Tomcat连接在事务中处于空闲状态,hibernate,c3p0,Hibernate,C3p0,我们有一个使用Hibernate连接到postgre数据库的应用程序。我们使用C3P0作为连接池 persistence.xml: org.hibernate.ejb.HibernatePersistence ---类别-- 保存对象: 加载对象: @SuppressWarnings("unchecked") public List<Entity> findByProperty(String propertyName, final Object
保存对象: 加载对象:
@SuppressWarnings("unchecked")
public List<Entity> findByProperty(String propertyName, final Object value,
final int... rowStartIdxAndCount) {
try {
final String queryString = "select model from " + clazz.getName()
+ " model where model." + propertyName + "= :propertyValue";
Query query = EntityManagerHelper.getEntityManager().createQuery(
queryString);
query.setParameter("propertyValue", value);
if (rowStartIdxAndCount != null && rowStartIdxAndCount.length > 0) {
int rowStartIdx = Math.max(0, rowStartIdxAndCount[0]);
if (rowStartIdx > 0) {
query.setFirstResult(rowStartIdx);
}
if (rowStartIdxAndCount.length > 1) {
int rowCount = Math.max(0, rowStartIdxAndCount[1]);
if (rowCount > 0) {
query.setMaxResults(rowCount);
}
}
}
final List<Entity> result = query.getResultList();
return result;
} catch (RuntimeException re) {
re.printStackTrace();
throw re;
}
}
谢谢你的帮助!:) 我觉得您的配置不正确:
<property name="hibernate.connection.release_mode" value="auto" />
这将在非JTA环境中设置AFTER_事务发布模式
我不确定这是否能解决您的问题(因为您可能已经在after_事务模式下运行)。(如果无法修复,请发表评论,并进行更深入的调查)
编辑
顺便说一句,重建sessionFactory似乎很奇怪。SessionFactory通常是单例的,SessionFactory的主要目的是非常高效地构建新会话。一般来说,没有理由重新创建它(因为sessionFactory只依赖于静态数据,这既耗时又无用)
我可以看到重新创建sessionFactory的唯一原因是,如果您的应用程序在运行时更改了数据模型,即创建新表或列,那么新的会话工厂将看到这些更改,前提是您同时应用程序修改映射文件或字节码,以添加新的注释、字段和类。我想你没有那样做
编辑2
正如我在上一次编辑中所说:避免重建sessionFactory。将此方法设置为私有,以确保不会多次调用它。如果代码正在重新构建sessionFactory,则可能是问题的原因,因为新的sessionFactory可能会消耗一些连接(由于相关的C3PO设置)
另外一点:你说过当禁用延迟加载时:再也没有问题了。因此,这个问题也可能是由于为延迟加载而创建的会话没有正确关闭造成的。尝试调试延迟加载操作,以查看会话来自何处,以及会话是否已关闭
编辑3(作为对您上次评论的回复) 您面临着一个非常常见的架构设计问题,假设有两种方法可以解决它。好的和(非常)坏的 非常糟糕的一个:在视图中使用开放会话模式。 其思想是在生成视图时重新打开entityManager并重新附加实体,这样就不会出现延迟初始化异常。在短期内,这种方法会给你一种错误的感觉,认为你的应用程序运行良好。一旦它投入生产,您的数据库中会有许多并发用户和/或越来越多的记录:您就有很大的风险出现真正的大性能问题(内存使用和/或响应时间) (这些潜在问题的根本原因是,在开发小数据库时,您不会注意到这个或那个视图正在获取一个包含10个对象的惰性初始化集合…但在生产中,您的小集合将包含10000个对象!!!) 这些问题将很难解决,因为: -它们将出现在多个视图中 -它们将很难进行单元/负载测试(因为它们位于视图层) 在我看来,这种方法只能用于小型非关键应用程序,它们永远不会有巨大的负载或大量的数据 好方法:使用分层架构。 视图层不要触摸实体管理器。该层从控制器层接收要显示的数据,所有数据都在那里:不需要在这里获取惰性集合 控制器层有两个角色:
- 实现您的业务逻辑
- 管理entityManager生命周期(和事务边界),并提供可由DAO层使用的entityManager
private static EntityManagerFactory emf;
private static final ThreadLocal<EntityManager> threadLocal = new ThreadLocal<EntityManager>();
public static EntityManager getEntityManager() throws HibernateException {
EntityManager session = (EntityManager) threadLocal.get();
if (session == null || !session.isOpen()) {
session = (emf != null) ? emf.createEntityManager()
: null;
threadLocal.set(session);
}
return session;
}
java.lang.Exception: DEBUG -- CLOSE BY CLIENT STACK TRACE
at com.mchange.v2.c3p0.impl.NewPooledConnection.close(NewPooledConnection.java:491)
at com.mchange.v2.c3p0.impl.NewPooledConnection.close(NewPooledConnection.java:191)
at com.mchange.v2.c3p0.impl.C3P0PooledConnectionPool$1PooledConnectionResourcePoolManager.dest royResource(C3P0PooledConnectionPool.java:470)
at com.mchange.v2.resourcepool.BasicResourcePool$1DestroyResourceTask.run(BasicResourcePool.ja va:964)
at com.mchange.v2.async.ThreadPoolAsynchronousRunner$PoolThread.run(ThreadPoolAsynchronousRunn er.java:547)
<property name="hibernate.connection.release_mode" value="auto" />