使用hibernate缓存的高效查询

使用hibernate缓存的高效查询,hibernate,caching,jpa-2.0,Hibernate,Caching,Jpa 2.0,我将JPA与Hibernate实现结合使用。对于经验丰富的hibernate用户,我的问题可能是最基本的:基于hibernate一级缓存编写查询的最有效方法是什么 例如,我有实体A和实体B: @Entity class A{ private int ida; private int x; private String s; @OneToMany(mappedBy = "ida", cascade = CascadeType.ALL, fetch = F

我将JPA与Hibernate实现结合使用。对于经验丰富的hibernate用户,我的问题可能是最基本的:基于hibernate一级缓存编写查询的最有效方法是什么

例如,我有实体
A
和实体
B

@Entity
class A{
      private int ida;
      private int x;
      private String s;
    @OneToMany(mappedBy = "ida", cascade = CascadeType.ALL, fetch = FetchType.LAZY)
      private Set<B> Bset;
    }

@Entity
class B{
      private int ida;
      private String s2;
    }
@实体
甲级{
私人国际开发协会;
私人INTX;
私有字符串;
@OneToMany(mappedBy=“ida”,cascade=CascadeType.ALL,fetch=FetchType.LAZY)
专用集Bset;
}
@实体
B类{
私人国际开发协会;
私有字符串s2;
}
假设在同一个会话中可能发生多个流:

  • 获取
    A.x
  • 获取整个
    A
    实体
  • s2=“…”
    检查
    A
    是否包含
    B
    对于其中的每一个查询,我都可以

    • 编写一个特定的查询,通过
      ida
      s2
      获取
      a.x
      /
      B
    • 假设Hibernate保存缓存并始终获取
      A
      对象,或者
      A.Bset()
      然后java循环以获取所需的
      B
      内部
      Bset()
    最有效的方法是什么


    感谢您

    对于用例1和用例2,我只需加载整个实体。第二级缓存同样可以正常工作。除非您的
    A
    对象非常大(有很多属性),否则您不会看到与以下对象相比的任何差异:

    SELECT a.x FROM A a WHERE a.id = :id
    
    更糟糕的是,使用上面的查询不会利用二级缓存

    第三个用例更有趣。这在很大程度上取决于您的需求,但合理的平衡是使用如下查询:

    SELECT B b
    WHERE b.s2 == :s2
      AND b.a = :a
    
    如果查询返回某个内容,则表示
    a
    包含
    b
    和给定的
    s2
    。这应该比懒洋洋地加载
    Bset
    并在其上迭代要快得多。考虑启用查询缓存。


    但是,如果
    Bset
    通常很小,并且您使用即时抓取,那么Java中的简单过滤可能会更好。这实际上取决于您的体系结构。

    只是一个警告,我认为上面的a和B之间的映射不起作用。当在关系的单方使用mappedBy时,还需要在B中映射反向关系

    @Entity
    class B{
          @ManyToOne
          @JoinColumn(name="aid")
          private A a;
          private String s2;
        }
    
    一对一的单向关系并不被真正推荐

    在回答您的问题时,高效使用会话缓存的关键是尽可能使用get()。因此,如果您可以通过其@Id获取A,那么您可以遍历映射的B集合来找到您感兴趣的实例

    使用get将确保如果您要查找的实例在缓存中,它将被返回(非常快),如果它不在缓存中,它将被添加到缓存中,然后返回给您。然后,下次您通过@Id请求它时,它将从缓存中返回


    无论何时使用HQL并强制Hibernate执行查询,您都将绕过会话缓存,直接进入数据库。如果您发现自己需要执行未命中缓存的查询,则可能值得研究查询缓存。

    谢谢您的回答。您写道:“那么下次您通过@Id请求它时,它将从缓存中返回。”。我从不按ID列查询,而是按@UniqueConstraint查询。它仍然会从缓存中返回吗?(equals和hashcode也基于UniqueConstraint)我认为不会。据我所知,会话缓存本质上是ID到对象的一个大映射。因此,要从中获取实体,您必须使用Id。谢谢,这解决了我的一些用例。如果一旦我需要一个B行,我将需要整个Bset,建议怎么做?我认为急切抓取会为A.B集逐个带来B行。不,急切抓取实际上是用来防止逐个抓取(臭名昭著的N+1问题)。通过快速获取,Hibernate将为您创建一个连接查询,并使用一个SQL一次性获取所有
    B
    s的
    a
    。这是使用@FetchMode(连接)配置的