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

Raj*_*dra 11 java hibernate servlets jpa java-ee

在其中一个应用程序中,我看到实体管理器是"按用户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
}
Run Code Online (Sandbox Code Playgroud)
  1. 这个设计有什么潜在的问题.
  2. 如果100K用户同时登录到应用程序,我们将用完jdbc连接怎么办?
  3. 每个实体管理器是否都有与之关联的单独JDBC连接?

Ser*_*sta 8

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

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

我在使用Hibernate的旧应用程序中看到过这样的设计,其中Hibernate会话(或多或少等同于EntityManager)存储在http会话中.它背后的理性是,由于HibernateSession包含一个缓存,它可以加速应用程序.实际结果是应用程序需要大量内存才能支持数百个用户,并且在没有完全重写的情况下永远不会扩展到数千个用户.

我知道我在这里只回答了1个问题,但我认为jdbc连接问题不是主要问题.Hibernate实验表明,我们可以通过调整Tomcat的池来快速回收jdbc连接来管理jdbc会话的问题,当然还可以增加池大小但是可以接受的限制.因为我认为主要的EntityManager实现能够在它们被关闭时自动请求新的jdbc会话(作为Hibernate会话).


col*_*ict 8

2和3的答案是肯定的.至于Q1:

您将遇到的一个问题是,会话通常在上次访问后持续2到24小时(或更长时间).这意味着您的会话对象将尝试维持EntityManager打开,并且EntityManager将尝试使JDBC连接保持活动并且独占于自身.即使每小时有50个用户,由于这个原因,您已经拥有大量异常和错误500页.

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

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