Hibernate在访问关联实体的id时生成SQL查询

我有Hibernate Entities看起来像这样(getters和setter被遗漏):

@Entity public class EntityA { @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = "parent_id") private EntityB parent; } @Entity public class EntityB extends SuperEntity { @OneToMany(mappedBy = "parent") @Fetch(FetchMode.SUBSELECT) @JoinColumn(name = "parent_id") private Set children; } @MappedSuperclass public class SuperEntity { @Id @GeneratedValue(strategy = GenerationType.AUTO) @Column(name = "id") private long itemId; } 

当我查询EntityA时,它加载正常,父关联被Hibernate代理替换(因为它是Lazy)。 如果我想访问父母的id,我执行以下调用:

 EntityA entityA = queryForEntityA(); long parentId = entityA.getParent().getItemId(); 

据我所知,调用不应该向数据库进行往返,因为Id存储在EntityA表中,并且代理应该只返回该值。 但是,在我的情况下,这将生成一个SQL语句,该语句提取EntityB,然后才返回Id。

我该如何调查这个问题? 导致这种错误行为的可能原因是什么?

据我所知,调用不应该向数据库进行往返,因为Id存储在EntityA表中,并且代理应该只返回该值。

使用属性访问类型 。 您遇到的行为是字段访问类型的“限制”。 以下是Emmanuel Bernard的解释:

这是不幸的,但预计。 这是现场级访问的限制之一。 基本上我们无法知道getId()确实只能访问id字段。 所以我们需要加载整个对象才能安全。

所以将代码更改为:

 @Entity public class EntityA { private EntityB parent; @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = "parent_id") public EntityB getParent() { return parent; } ... } @MappedSuperclass public class SuperEntity { private long itemId; @Id @GeneratedValue(strategy = GenerationType.AUTO) @Column(name = "id") public long getItemId() { return itemId; } ... } 

相关问题

  • Hibernate Annotations – 哪个更好,是字段还是属性访问?

参考

  • 在字段上使用注释时,在getId调用时加载代理
  • proxy getId =>为什么生成sql!
  • HHH-3718 (如果这个问题可以解决的话)

你说的有意义 – 因为EntityA包含父ID,它不会成为数据库命中。 我只是不确定getParent()调用是否实际加载了EntityB对象,无论你是否感兴趣的是ID。 如果要保存数据库命中,可以尝试将子集合(以及任何其他字段)标记为Lazy。

 @Entity public class EntityB : SuperEntity { @OneToMany(mappedBy = "parent", fetch = FetchType.LAZY) @Fetch(FetchMode.SUBSELECT) @JoinColumn(name = "parent_id") private Set children; }