我们正在开发一个 (JavaSE-) 应用程序,它通过持久的 tcp 连接与许多客户端通信。客户端连接,执行一些/许多操作(更新到 SQL 数据库)并关闭应用程序/与服务器断开连接。我们正在使用 Hibernate-JPA 并使用 ThreadLocal 变量自行管理 EntityManager 生命周期。实际上,我们在每个客户端请求上都创建了一个新的 EntityManager 实例,到目前为止效果很好。最近我们进行了一些分析,发现 hibernate 在每个 UPDATE 语句之前对数据库执行一个 SELECT 查询。那是因为我们的实体处于分离状态,并且每个新的 EntityManager 首先将实体附加到持久性上下文。当服务器处于负载下时(因为我们有一个写入密集型应用程序),这会导致大量的 SQL 开销,我们试图消除这种泄漏。
- 首先,我们想到了二级缓存。但是,我们发现每当添加或删除新项目时,hibernate 都会使其查询缓存和集合缓存无效。
- 再三考虑,我们评估是否只要客户端在服务器上登录就让 EntityManager 保持运行状态。但我想知道这是否是“最佳实践”,因为存在一些缺点:线程安全、EntityManager 实例的管理开销等。
简而言之:我们正在寻找一种方法来在每次更新之前摆脱这些 SELECT 语句。有什么想法吗?
最佳答案
在重新附加分离实体时摆脱 select
语句的一种可能方法是使用特定于 Hibernate 的 update()
操作而不是 merge()
。
update()
无条件运行 update
SQL 语句并使分离的对象持久化。如果 session 中已存在具有相同标识符的持久对象,则抛出异常。因此,当您确定:
- 分离对象包含应保存在数据库中的修改状态
- 保存该状态是为该请求打开 session 的主要目标(即没有其他操作在该 session 中加载具有相同 ID 的实体)
在 JPA 2.0 中,您可以访问特定于 Hibernate 的操作,如下所示:
em.unwrap(Session.class).update(o);
另请参阅:
关于java - EntityManager 生命周期和持续的客户端-服务器-通信,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8038252/