关于java:EntityManager生命周期和持久的客户端-服务器-通信

EntityManager lifecycle and persistent client-server-communication

我们正在开发(JavaSE-)应用程序,该应用程序通过持久的tcp连接与许多客户端进行通信。客户端连接,执行一些/许多操作(已更新为SQL数据库)并关闭应用程序/与服务器断开连接。我们正在使用Hibernate-JPA,并使用ThreadLocal-variable自行管理EntityManager-lifecycle。实际上,到目前为止,我们在每个客户端请求上都创建了一个新的EntityManager-instance。最近,我们进行了一些分析,发现hibernate在每个UPDATE语句之前对数据库执行SELECT查询。那是因为我们的实体处于分离状态,并且每个新的EntityManager都会首先将该实体附加到持久性上下文。当服务器处于负载状态时,这会导致大量的SQL开销(因为我们有一个写繁重的应用程序),并且我们试图消除这种泄漏。

  • 首先,我们考虑了二级缓存。但是,我们发现,每当添加或删除新项目时,hibernate会使它的查询缓存和集合缓存失效。
  • 再次考虑,只要客户端在服务器上登录,我们就评估是否保持EntityManager正常运行。但是我不知道这是否是"最佳实践",因为存在一些缺点:线程安全,EntityManager实例的管理开销等。

简而言之:我们正在寻找一种在每次UPDATE之前摆脱那些SELECT语句的方法。有什么想法吗?


重新连接分离的实体时摆脱select语句的一种可能方法是使用特定于Hibernate的update()操作而不是merge()

update()无条件运行update SQL语句,并使分离的对象持久化。如果会话中已经存在具有相同标识符的持久对象,它将引发异常。因此,当您确定以下内容时,这是一个不错的选择:

  • 分离的对象包含应保存在数据库中的已修改状态
  • 保存该状态是为此请求打开会话的主要目标(即,没有其他操作在该会话中加载具有相同ID的实体)
  • 在JPA 2.0中,您可以按以下方式访问特定于Hibernate的操作:

    1
    em.unwrap(Session.class).update(o);

    另请参见:

    • 11.6。修改分离的对象


    一个可能的选择是对更新语句使用StatelessSession。我已经在"大量写入"应用程序中成功使用了它。