Java EntityManager生命周期和持久客户机-服务器通信

Java EntityManager生命周期和持久客户机-服务器通信,java,hibernate,jpa,entitymanager,Java,Hibernate,Jpa,Entitymanager,我们正在开发一个(JavaSE-)应用程序,它通过持久tcp连接与许多客户机通信。客户端连接、执行一些/许多操作(更新为SQL数据库)并关闭应用程序/断开与服务器的连接。我们正在使用Hibernate JPA,并使用ThreadLocal变量自行管理EntityManager生命周期。实际上,我们在每个客户机请求上创建了一个新的EntityManager实例,到目前为止效果良好。最近我们分析了一下,发现hibernate在每个UPDATE语句之前都会对DB执行SELECT查询。这是因为我们的实体

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

  • 首先,我们考虑了二级缓存。然而,我们发现,每当添加或删除新项时,hibernate就会使其查询和集合缓存失效
  • 再想一想,我们评估是否在客户端登录到服务器时保持EntityManager处于运行状态。但我想知道这是否是一种“最佳实践”,因为它有一些缺点:线程安全,管理EntityManager实例的开销,等等

简而言之:我们正在寻找一种方法,在每次更新之前去掉那些SELECT语句。有什么想法吗?

一个可能的选择是使用update语句。我已经在我的“写重”应用程序中成功地使用了它。

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

update()
无条件运行
update
SQL语句,并使分离的对象持久化。如果会话中已存在具有相同标识符的持久对象,则会引发异常。因此,如果您确信:

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

    em.unwrap(Session.class).update(o);
    
    另请参见:


    听起来对我们很有用。我试试看。