当前位置: 首页 > 知识库问答 >
问题:

Hibernate、C3P0、postgres、Tomcat连接在事务中空闲

段干英杰
2023-03-14

我们有一个应用程序使用Hibernate连接到postgre数据库。我们使用C3P0作为连接池。

org.hibernate.ejb.hibernatepersistence

---类---



数据库---”/">







正在保存对象:

public Entity saveOrUpdate(Entity entity, User u) {  
EntityTransaction tx = EntityManagerHelper.getEntityManager().getTransaction();  
try {  
  if(!tx.isActive())  
      tx.begin();  
          Entity result = null;  
      if (getID(entity) == null) {  
      EntityManagerHelper.getEntityManager().persist(entity);  
  } else {  
      result = EntityManagerHelper.getEntityManager().merge(entity);  
  }  
  tx.commit();    
  return result;  
  } catch (RuntimeException re) {  
      re.printStackTrace();  
      tx.rollback();  
      throw re;  
  }  
}  

正在加载对象:

@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;
        }
    }  

创建EntityManagerFactory并获取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)  

谢谢你的帮助!:)

共有1个答案

程墨竹
2023-03-14

您的配置在我看来不正确:

  1. transaction-type=“resource_local”表示您不在JTA环境中。
  2. 属性name=“hibernate.connection.release_mode”value=“after_statement”与auto-commit=false结合使用的情况非常少见。

“after_statement”只能在连接提供程序支持积极版本(并且能够为同一事务中的每个语句返回相同的连接)时使用。

hibernate可能会忽略AFTER_STATEMENT(因为hibernate检测到此发布模式与您的设置不兼容),而使用AFTER_TRANSACTION...但为了确保你没有错误地使用它,你把它

 <property name="hibernate.connection.release_mode" value="auto" />

这将在非JTA环境中设置AFTER_TRANSACTION发布模式。

我不确定这会修复您的问题(因为有一些可能您已经在after_transaction模式下运行)。(如果它没有修复它,请评论和一个更深入的调查将被要求)。

我能看到的重新创建sessionFactory的唯一原因是如果您的应用程序在运行时更改了数据模型--即。创建新的表或列(只有在应用程序同时修改映射文件或字节代码以添加新的注释、字段和类时,这些更改才会被新的会话工厂看到)。我想你不会那样做的。

编辑2

正如我在前面编辑中所说:避免重建SessionFactory。将此方法设为私有,以便确保不会多次调用它。如果您的代码正在重新构建sessionFactory,它可能是问题的原因,因为新的sessionFactory可能会消耗一些连接--由于相关的C3PO设置)。

编辑3(作为对您上次评论的回复)

您正面临一个非常常见的建筑设计问题,假设有2种方法可以解决它。好的和(非常)坏的。

(非常)糟糕的一个:在视图中使用open session模式。

在我看来,这种方法只能用于小的--非关键的--永远不会有巨大负载或大数据量的应用程序。

好的一个:使用分层架构

视图层不接触实体管理器。这一层从控制器层接收要显示的数据,所有的数据都在那里:这里不需要取懒散的集合。

  • 实现您的业务逻辑
  • 管理entityManager生命周期(和事务边界),并提供DAO层可以使用的entityManager。

另外,控制器层必须向视图层提供完整的对象图。完整对象图意味着如果视图需要显示来自该集合的数据,视图层将不会接收到未初始化的惰性集合。

道层:

DAO层必须提供广泛的查询来获取该实体,不管它是否具有懒惰集合,以便满足控制器层的所有需求。

分层体系结构方法的主要优点是,您在开发过程中很快就会看到视图的需求,并且您将能够在需要时调整和优化您的查询。(即,您需要一个一个地修复所有的lazy-init异常,但这将使您对视图的需求有一个很好的了解)

 类似资料:
  • 我的JAVA应用程序使用多线程一次处理多个请求。因此,不同的请求在同一时间用不同的线程进行处理。 如果我观察数据库中打开的会话,有10个打开的会话(在c3p0中配置的最大数量),但它们都是空闲的。有没有一种方法可以让c3p0释放一些空闲连接,这样,至少有一个线程结束它的进程(增加最大连接数)?

  • C3P0不会在事务完成后释放连接。下面是堆栈跟踪: 池配置和事务配置如下: 如有任何建议,我将不胜感激

  • null 如果我理解正确的话,我们应该在启动时有1个空闲连接,根据负载从0到3,对吗? 正在发生的情况是:启动时1个连接,如果负载较低,最多3个空闲连接,高负载后超过3个空闲连接。然后这些连接不会立即关闭,我们不知道它们何时/是否会关闭(有时它们中的一些会关闭)。 所以问题是:这种行为正常吗? DAO子类的使用示例:

  • 我在上一篇文章java中试图解决我的问题。sql。SQLRecoverableException:已关闭连接。我尝试了c3p0连接。财产如下:, 在JBOSS中部署之后,我开始测试我的web。一开始,它工作得很好,甚至更快。10分钟后,继续加载并超时。当通过服务器时。日志我得到了如下一些警告消息。 请给出一些解决这个问题的想法。

  • 这与之前未解决的一个帖子有关:这里C3P0似乎在Heroku上初始化连接池后立即进入死锁。这个问题不会发生在我的本地邮件上。 [DEBUG]“com.mchange.v2.resourcepool.basicresourcepool”2015-07-05 07:12:59,132:成功终止获取系列。递减的pending_acquires 1,Attests_Retailing:30 [DEBUG]

  • 我有一个应用程序,它将C3p0与Hibernate5和Hibernate使用。我想尝试使用Hikari,但我无法运行该应用程序。 专家 Hibernate版本为:5.2.17.Final Spring配置 我尝试了上述方法的不同排列,包括将用户名和密码直接传递给数据源: 但是我总是以这个错误结束: 这是由光函数引起的: