简体   繁体   English

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

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

we have a n+1 select problem with Hibernate 3.3. Hibernate 3.3 有一个 n+1 select 问题。

For simplicity's sake, I'll just do a short abstract example.为简单起见,我将只做一个简短的抽象示例。

Suppose we have the following simple classes:假设我们有以下简单的类:

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")
}

So as you can see SubEntity has a relation to MainEntity that is expressed by two properties, where the mainId property is the one responsible for managing the relation/foreign key.如您所见, SubEntityMainEntity的关系由两个属性表示,其中mainId属性是负责管理关系/外键的属性。

This works quite well and perfectly fits our needs.这工作得很好,完全符合我们的需求。

However, there's one problem with eagerly loading the SubEntity along with the MainEntity .但是,急切地加载SubEntityMainEntity存在一个问题。

Suppose I have a query that returns a collection of MainEntity .假设我有一个返回MainEntity集合的查询。 With the current setup, Hibernate will issue n + 1 selects: the query itself + n selects for each SubEntity .使用当前设置, Hibernate 将发出 n + 1 个选择:查询本身 + n 为每个SubEntity选择。

Of course I could add a join fetch to the query, but I'd rather like Hibernate to do that automatically.当然,我可以在查询中添加join fetch ,但我更希望 Hibernate 自动执行此操作。 Thus I tried adding @Fetch( FetchMode.JOIN ) , but that didn't do anything.因此我尝试添加@Fetch( FetchMode.JOIN ) ,但这并没有做任何事情。

I would also have no problem using @Fetch( FetchMode.SUBSELECT ) , which should reduce the select statements to 2 - the original query and a select for the sub entities (at least that's what happens on another property annotated with @CollectionOfElements and @Fetch( FetchMode.SUBSELECT ) ).使用@Fetch( FetchMode.SUBSELECT )也没有问题,这应该将 select 语句减少到 2 - 原始查询和子实体的 select (至少这是在另一个用@CollectionOfElements@Fetch( FetchMode.SUBSELECT )注释的属性上发生的情况@Fetch( FetchMode.SUBSELECT ) )。


So the question is: how would I tell Hibernate to automatically join fetch or use a single select in order to eagerly load the sub entities?所以问题是:我如何告诉 Hibernate自动加入 fetch 或使用单个 select 以便急切地加载子实体? Am I missing something?我错过了什么吗?

Thanks in advance,提前致谢,

Thomas托马斯

PS: One thing that might be a problem might be the mappedBy = "main" which doesn't reference the actual id column, but I can't change it to mappedBy = "id" . PS:可能有问题的一件事可能是mappedBy = "main"没有引用实际的 id 列,但我无法将其更改为mappedBy = "id"

If you want to shared primary keys between MainEntity and SubEntity use PrimaryKeyJoinColumn and MapsId annotation.如果要在 MainEntity 和 SubEntity 之间共享主键,请使用PrimaryKeyJoinColumnMapsId注释。

By using PrimaryKeyJoinColumn the entity is loaded by joining the MainEntity table with the SubEntity table using the same primary key.通过使用PrimaryKeyJoinColumn ,通过使用相同的主键将MainEntity表与SubEntity表连接来加载实体。 It should resolve the n+1 problems.它应该可以解决 n+1 个问题。

The MapsId annotation ask Hibernate to copy the identifier from another associated entity in our example will copy the SubEntity.mainEntity.id to SubEntity.id . 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 Reference Documentation: Hibernate 参考文档:

PrimaryKeyJoinColumn PrimaryKeyJoinColumn
MapsId MapsId

There are three options to avoid the questions n +1:有三个选项可以避免问题 n +1:

 Lot size

 subselect

 Make a LEFT JOIN in the query

Here FAQ1 Here FAQ2这里常见问题1这里常见问题2

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

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