小编典典

重用查询的一部分进行计数的Java编码最佳实践

hibernate

在实施对结果分页功能于hibernate,让计用户号码的,行的问题触发另一个问题对我来说,对
一些执行情况表示关注

现在您知道必须重用HQL查询的一部分来进行计数,如何有效地重用?

两个HQL查询之间的区别是:

  1. 选择是count(?),而不是pojo或属性(或列表)
  2. 提取不应发生,因此某些表不应联接
  3. order by应该消失

还有其他区别吗?

您是否有 编码最佳实践来有效地实现这种重用 (问题:努力,清晰,性能)?

一个简单的HQL查询示例:

    select       a     from A a join fetch a.b b where a.id=66 order by a.name
    select count(a.id) from A a                  where a.id=66

更新

我收到以下答案:

  • 使用 条件 (但我们主要使用HQL)
  • 处理String 查询(但每个人都同意这似乎很复杂,也不是很安全)
  • 包装查询 ,依靠数据库优化(但是有一种感觉,这是不安全的)

我希望有人会沿着另一条路径提供更多选项,这些路径与String串联更多相关。
我们可以使用公共部分来构建两个HQL查询 吗?


阅读 191

收藏
2020-06-20

共1个答案

小编典典

好问题。这是我过去所做的(您已经提到的许多事情):

  1. 检查是否存在 SELECT 子句。
    1. 如果不是,请添加 select count(*)
    2. 否则,请检查它是否具有 DISTINCT 或聚合函数。如果您正在使用ANTLR来解析查询,则可以解决这些问题,但是涉及很多。您最好将整个过程包装为select count(*) from ()
  2. 去掉 fetch all properties
  3. fetch如果要将HQL解析为字符串,请从联接中删除。如果您是使用ANTLR真正解析查询,则可以将其left join完全删除;检查所有可能的引用是很麻烦的。
  4. 去掉 order by
  5. 根据您在1.2中所做的事情,您需要删除/调整group by/ having

以上自然适用于HQL。对于Criteria查询,您只能做些限制,因为它不便于操作。如果您在Criteria之上使用某种包装层,则最终将得到ANTLR解析结果的(有限)子集,并且在这种情况下可以应用上面的大多数内容。

由于您通常会保留当前页面的偏移量和总计数,因此我通常会先使用给定的限制/偏移量运行实际查询,并且仅在count(*)返回的结果数大于或等于限制且偏移量为零时才运行查询(在所有其他情况下,我要么count(*)之前运行过,要么无论如何都要获得所有结果)。当然,对于并发修改,这是一种乐观的方法。

更新 (手工组装HQL)

我不太喜欢这种方法。当映射为命名查询时,HQL具有构建时错误检查的优势(从技术上来说,运行时是因为必须构建SessionFactory,尽管无论如何这通常是在集成测试中完成的)。当在运行时生成时,它会在运行时失败:-)进行性能优化也不是一件容易的事。

当然,同样的推理也适用于Criteria,但是由于定义良好的API(而不是字符串连接),因此更难解决。并行构建两个HQL查询(分页为一个,“全局计数”为一个)也会导致代码重复(并可能有更多的错误),或者迫使您在顶部编写某种包装层来为您完成。两种方法都不理想。而且,如果您需要从客户端代码执行此操作(如通过API进行操作),问题将变得更加严重。

实际上,我在这个问题上已经考虑了很多。Hibernate-Generic-
DAO的
Search API
似乎是一个合理的折衷方案。我对上述链接问题的回答中有更多详细信息。

2020-06-20