繁体   English   中英

Hibernate OneToOne 自动连接抓取(解决n+1问题)

[英]Hibernate OneToOne automatic join fetching (resolving n+1 problem)

Hibernate 3.3 有一个 n+1 select 问题。

为简单起见,我将只做一个简短的抽象示例。

假设我们有以下简单的类:

class MainEntity {
  @Id
  public Long id; //we have a table generator create this id

  @OneToOne ( mappedBy ="main" )
  public SubEntity subEntity;
}

class SubEntity {
 @Id
 @Column( name = "mainId" ) //note that this is the same column as the join column below
 public Long mainId; //in order to have the exact same id as the corresponding MainEntity

 @OneToOne ( fetch = FetchType.LAZY )
 @JoinColumn ( name = "mainId", insertable = false, updatable = false, nullable = false )
 public MainEntity main; //this is used for navigation and queries (" ... subentity.main = :x")
}

如您所见, SubEntityMainEntity的关系由两个属性表示,其中mainId属性是负责管理关系/外键的属性。

这工作得很好,完全符合我们的需求。

但是,急切地加载SubEntityMainEntity存在一个问题。

假设我有一个返回MainEntity集合的查询。 使用当前设置, Hibernate 将发出 n + 1 个选择:查询本身 + n 为每个SubEntity选择。

当然,我可以在查询中添加join fetch ,但我更希望 Hibernate 自动执行此操作。 因此我尝试添加@Fetch( FetchMode.JOIN ) ,但这并没有做任何事情。

使用@Fetch( FetchMode.SUBSELECT )也没有问题,这应该将 select 语句减少到 2 - 原始查询和子实体的 select (至少这是在另一个用@CollectionOfElements@Fetch( FetchMode.SUBSELECT )注释的属性上发生的情况@Fetch( FetchMode.SUBSELECT ) )。


join fetch or use a single select in order to eagerly load the sub entities?所以问题是:我如何告诉 Hibernate加入 fetch 或使用单个 select 以便急切地加载子实体? 我错过了什么吗?

提前致谢,

托马斯

PS:可能有问题的一件事可能是mappedBy = "main"没有引用实际的 id 列,但我无法将其更改为mappedBy = "id"

如果要在 MainEntity 和 SubEntity 之间共享主键,请使用PrimaryKeyJoinColumnMapsId注释。

通过使用PrimaryKeyJoinColumn ,通过使用相同的主键将MainEntity表与SubEntity表连接来加载实体。 它应该可以解决 n+1 个问题。

MapsId注释要求 Hibernate 从另一个关联实体复制标识符,在我们的示例中,会将SubEntity.mainEntity.id复制到SubEntity.id

@Entity
public class MainEntity {

    @Id
    @GeneratedValue(strategy=GenerationType.IDENTITY)
    @Column(name = "main_Id")
    private Long id;

    @OneToOne(cascade = CascadeType.ALL)
    @PrimaryKeyJoinColumn
    private SubEntity  subEntity ;
}


@Entity
public class SubEntity 
{
    @Id @Column(name="main_Id_FK") Long id;

    @MapsId 
    @OneToOne
    @JoinColumn(name = "main_Id_FK")    
    @PrimaryKeyJoinColumn
    private MainEntity mainEntity;        

}

Hibernate 参考文档:

PrimaryKeyJoinColumn
MapsId

有三个选项可以避免问题 n +1:

 Lot size

 subselect

 Make a LEFT JOIN in the query

这里常见问题1这里常见问题2

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM