Hibernate JPA 每次使用相同的参数值调用 findOne(字符串 id) 时都会生成选择查询



在我们的例子中,Hibernate findOne(String id(需要很多时间(超过300毫秒(。这也不一致。对于某些请求,它会在不到 100 毫秒的时间内返回结果。

因此,我们希望提高findOne的性能,其中不应花费超过100毫秒的时间。由于该表包含超过 100k 条记录,因此我们为选择查询中涉及的实体设置了索引。

我们为每个客户端请求调用此 findOne 方法。只有 where 子句中的值会更改,而不会更改其中涉及的列或实体。

所以基本上,如果Hibernate可以创建/生成一次选择查询并将其重用于存储库上的所有findOne调用,那就太好了。

有人可以帮助我吗?

您可以在此处考虑一些优化。

  1. HTTP 会话
  2. 二级缓存
  3. 尽可能使用@NamedQuery
  4. 不要使用基于字符串的主键。

HTTP 会话缓存

当客户端进行身份验证且值不存在时,您始终可以使用#findOne方法获取的对象存储在 HTTP 会话中。 这将消除对所有后续经过身份验证的请求的查询。 您必须考虑的唯一问题是,如果当前用户修改了相关对象,则需要将会话中的值替换为更新的副本。

许多 Web 应用程序都使用此机制。 如果您曾经登录过信用卡或银行的在线帐户系统并致电他们进行更改,您可能已经注意到您必须注销并重新登录才能看到这些更改。 这是相同的概念。

二级缓存

此解决方案甚至适用于使用休眠的非基于 HTTP 的应用程序。 在这种情况下,您有一个位于应用程序端的数据存储,您可以将其配置为存储不经常更改的信息的查询结果。 如果条目尚未过期,Hibernate不会将每个查询的数据库和网络成本转移到缓存中存在的内容,而是首先从缓存中解冻。

2LC 的好处是,如果要缓存,您可以配置每个查询,还可以为每个实体类型配置不同的超时和其他配置选项。

@NamedQuery

有时,您执行的复杂查询是以重新分析 JPQL/HQL 为代价的。 如果您发现这是一个问题,您可能需要查看是否可以将查询移动到静态@NamedQuery

@NamedQuery的好处是,底层解析树的解析、验证和构建在应用程序 boostrap 时完成一次。 这意味着在运行时,Hibernate只是获取该定义,获取预先生成的SQL,应用参数绑定并将其交给数据库。 缺少参数类型验证,开销非常小。

没有基于字符串的键

根据您的数据库平台,基于字符串的主键的性能可能比其数字计数器部分差得多,尤其是在查询涉及联接时。 如果您的字符串字段配置为支持 unicode(例如 NVARCHAR 或 NCHAR 列(,则会使问题更加复杂。

将 String 用于@NaturalId是完全可以的,因为您通常只是对该字段应用 where 谓词,您可以在其中根据查询的要求应用各种索引。

但我建议您的查询是否使用基于字符串的主键,将其移动到@NaturalId并使用基于代理项数字的主键。 您会注意到表联接的性能将显著提高,因为它们之间的比较和哈希查找要快得多。

最新更新