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

时间:2016-10-01 09:34:14

标签: java hibernate jpa servlets 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
}
  1. 此设计存在哪些潜在问题。
  2. 如果100K用户同时登录到应用程序,我们将用完jdbc连接怎么办?
  3. 每个实体管理器是否都有一个与之关联的独立JDBC连接?

2 个答案:

答案 0 :(得分:8)

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

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

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

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

答案 1 :(得分:8)

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

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

我相信Serge Ballesta列出了这种方法会引起的其他主要问题。

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