Java 在web应用程序中为每个HttpSession创建EntityManager的潜在问题

Java 在web应用程序中为每个HttpSession创建EntityManager的潜在问题,java,hibernate,jpa,servlets,jakarta-ee,Java,Hibernate,Jpa,Servlets,Jakarta Ee,在其中一个应用程序中,我看到EntityManager是“每用户HttpSession”创建的,EntityManagerFactory只创建一次 应用程序中未使用Spring或EJB。 实体管理器缓存在http会话中,并在会话无效时关闭 public EntityManager getEntityManager() { //Logic to get entity manger from session //If its present , then return /

在其中一个应用程序中,我看到EntityManager是“每用户HttpSession”创建的,EntityManagerFactory只创建一次

应用程序中未使用Spring或EJB。 实体管理器缓存在http会话中,并在会话无效时关闭

public EntityManager getEntityManager() { 
    //Logic to get entity manger from session
    //If its present , then return 
    //Else create new one , entityManagerFactory.createEntityManager();
    //Put it into session and then return.
    //Returned entity manager is not closed by dao methods , 
    //but clear() is invoked
}
  • 这种设计有哪些潜在问题
  • 如果同时有10万用户登录到应用程序,我们会耗尽jdbc连接吗
  • 是否每个实体管理器都有一个单独的与之相关联的JDBC连接

  • 请不要这样做:当最佳实践建议设计仅在一层和相邻层之间具有(松散)链接的分层应用程序时,您正在将持久层直接绑定到web层

    对于这种设计可能出现的实际问题,一个是内存浪费。由于HTTP是一种未连接的协议,如果客户端只关闭浏览器而没有显式断开连接,则会话不会立即关闭,只会在会话超时时收集。这就是为什么最佳实践建议在会话中存储尽可能少的对象并且尽可能小的原因。顺便说一句,如果您想在服务器场上为应用程序提供服务,会话中存储的对象应该是可序列化的,我不确定实体管理器是否可用。至少它的接口定义不能保证

    我在使用Hibernate的旧应用程序中看到过这样的设计,其中Hibernate会话(或多或少相当于EntityManager)存储在http会话中。其背后的理由是,由于HibernateSession包含一个缓存,它可以加快应用程序的速度。实际结果是,应用程序需要大量内存才能支持几百个用户,如果不进行完全重写,将永远无法扩展到数千个用户


    我知道我在这里只回答了1个问题,因为我真的认为jdbc连接问题不是主要问题。Hibernate实验表明,我们可以通过调整Tomcat的池来管理jdbc会话的问题,以便很快回收jdbc连接,当然也可以将池大小增加到可接受的限度。因为我假设主要的EntityManager实现能够在其会话关闭时自动请求新的jdbc会话(就像Hibernate会话那样)。

    对2和3的回答是肯定的。至于第一季度:

    您将遇到的一个问题是,会话通常在最后一次访问后持续2到24小时(或更长)。这意味着您的会话对象将尝试保持EntityManager的打开状态,EntityManager将尝试保持JDBC连接的活动状态,并对其自身进行独占。即使每小时有50个用户,您也会因此而有大量异常和错误页面

    我相信Serge Ballesta列出了这种方法将导致的其他主要问题


    更安全的解决方案是在所有URL上使用静态
    ThreadLocal
    单例访问和
    javax.servlet.Filter
    ,并使用try-finally语句确保EntityManager在每次请求时正确关闭。否则,可能发生的任何异常都会使连接悬空并导致其他问题。

    它会提醒示例EntityManager存储为ThreadLocal的位置。相关线程:您真的在使用完整的JavaEE,还是仅仅是一个servlet容器,比如Tomcat?仅仅是servlet容器Tomcat。