我有一个实体A,它具有-B实体,而B具有-A与@OneToOne双向关联。
现在,当我找到所有A记录时,hibernate使用B上的左外部联接执行两个查询,如下所示:
select a.id, a.id_b, a.field1, b.id, b.field1 from A as a, B as b left outer join b ON b.id=a.id_b;
select a.id, a.id_b, a.field1, b.id, b.field1 from A as a, B as b left outer join b ON b.id=a.id_b WHERE b.id=?
第一次查询会加载A和B字段,但可以,但是为什么要执行第二次查询来重新加载A?我认为此查询将B中的A内容加载,但此A显然是包含B的A
…因此它已经加载了第一个查询,不是吗?
-编辑-
实体A:
@Entity
public class A implements Serializable{
// id and other ecc ecc
@OneToOne
@JoinColumn(name="id_b")
B b;
}
实体B:
@Entity
public class B implements Serializable{
// id and other ecc ecc
@OneToOne(mappedBy="b")
A a;
}
就是这种情况,在A上的findAll需要两个查询…为什么?
如果A和B 共享同一个主键列 ,则这两个实体 通过使用它们的主键进行连接
,这时就吹响了,您应该改用@PrimaryKeyJoinColumn
@Entity
public class A implements Serializable {
private MutableInt id = new MutableInt();
private B b;
public void setIdAsMutableInt(MutableInt id) {
this.id = id;
}
@Id
@GeneratedValue
public Integer getId() {
return id.intValue();
}
public void setId(Integer id) {
this.id.setValue(id);
}
/**
* Any ToOne annotation, such as @OneToOne and @ManyToOne, is EARGELY loaded, by default
*/
@OneToOne(fetch=FetchType.LAZY)
@PrimaryKeyJoinColumn
@Cascade(CascadeType.SAVE_UPDATE)
public B getB() {
return b;
}
public void setB(B b) {
b.setIdAsMutableInt(id);
this.b = b;
}
}
和B注意 ,* 由于 @PrimaryKeyJoinColumn, 您不需要 mapedBy 属性 *
@Entity
public class B implements Serializable {
private MutableInt id = new MutableInt();
private A a;
public void setIdAsMutableInt(MutableInt id) {
this.id = id;
}
@Id
public Integer getId() {
return id.intValue();
}
public void setId(Integer id) {
this.id.setValue(id);
}
@OneToOne(fetch=FetchType.LAZY)
@PrimaryKeyJoinColumn
public A getA() {
return a;
}
public void setA(A a) {
this.a = a;
}
}
测试(您可以测试是否需要)
A a = new A();
B b = new B();
a.setB(b);
/**
* b property will be saved because Cascade.SAVE_UPDATE
*/
Serializable id = session.save(a);
b = (B) session
.createQuery("from B b left join fetch b.a where b.id = :id")
.setParameter("id", id)
.list()
.get(0);
Assert.assertEquals(b.getId(), b.getA().getId());
注意,我使用MutableInt字段(由Integer属性 封装 )而不是Integer,因为Integer
是不可变的类型,A和B都共享SAME分配的ID
但是,如果A和B 通过使用除主键之外的其他键进行连接 ,则应使用@JoinColumn和maptedBy(双向关系,右),如下所示
@Entity
public class A implements Serializable {
private Integer id;
private B b;
@Id
@GeneratedValue
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
/**
* mappedBy="a" means: Look at "a" field / property at B Entity. If it has any assigned value, join us Through B_ID foreign key column
*/
@OneToOne(fetch=FetchType.LAZY, mappedBy="a")
/**
* Table A has a foreign key column called "B_ID"
*/
@JoinColumn(name="B_ID")
@Cascade(CascadeType.SAVE_UPDATE)
public B getB() {
return b;
}
public void setB(B b) {
this.b = b;
}
}
和B
@Entity
public class B implements Serializable {
private Integer id;
private A a;
public void setIdAsMutableInt(MutableInt id) {
this.id = id;
}
@Id
@GeneratedValue
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
@OneToOne(fetch=FetchType.LAZY)
public A getA() {
return a;
}
public void setA(A a) {
this.a = a;
}
}
去测试
A a = new A();
B b = new B();
/**
* Set up both sides
* Or use some kind of add convenience method
*/
a.setB(b);
b.setA(a);
/**
* b property will be saved because Cascade.SAVE_UPDATE
*/
Serializable id = session.save(a);
b = (B) session
.createQuery("from B b left join fetch b.a where b.id = :id")
.setParameter("id", id)
.list()
.get(0);
通过使用所有者方B, 您将获得两个select语句。 这是因为B表 不包含任何指向表A的外键列, 但是通过使用
“从A左连接获取ab,其中a.id =:id”
您将 仅 获得 一条select语句, 因为A知道如何使用其B_ID外键列来检索其联接的B。
问题内容: 我有一个我认为应该很普遍的问题,但找不到答案。 我有2个对象:组和用户。我的课程如下所示: 现在,当我尝试从数据库中获取用户时,它带来了所有组,所有组都带来了所有用户,依此类推。最后,我遇到了stackoverflow异常。 如何解决此问题,并且仍然具有双向关联以及到达列表中对象的能力? 问题答案: 如果使用属性(无论如何都应使用)将双向关联的一侧设为关联的 拥有 侧,是否会遇到相同的
问题内容: 我相信只有两种使用Hibernate加载对象的方法,即延迟加载和一种渴望加载。延迟加载有其自身的优势,它不会加载很多对象,而只是在需要时才加载它们。我还了解到,如果您想强制为一个对象加载所有子代,则只需调用即可。假设我们有以下对象 假设我们有一些客户在我们的系统中有订单,并且该订单可能不止一个甚至为空。所以我的问题是,在这种情况下始终使用渴望加载会更好吗?我们需要与客户相关的订单的大小
问题内容: SQLAlchemy支持渴望加载关系,这基本上是一条语句。但是,如果模型具有两个或多个关系,则可能是非常庞大的联接。例如, 该查询的性能实在是太差了,因为中和会产生一个巨大的表。但是和在这里没有关系,因此它们不应该是。它应该是两个分开的查询。并且由于会话具有某种程度的缓存,因此我将查询更改为此。 这次的性能要好得多。但是,我不认为这样做是正确的。我不确定会话结束时标签缓存是否会过期。
在我的控制器我有以下代码: 在这两种方法中,只读取查询的第一个条件。 我想让1子句和1在急切加载的数据中被过滤。 有什么我错过了做的吗?我把它编错了吗?
问题内容: 我看到很多帖子,其中Eager fetch在休眠状态下执行子表父表的左连接。但是当我使用springboot时,hibernate会触发单独的sql查询- 意味着一个针对父表的选择查询和一个针对子表的选择查询。为什么有区别?springboot是否进行了升级,或者我做错了什么? 以下是我正在使用的实体: 订单实体: 客户实体: 控制器: 仓库: 以下是正在执行的查询: 编辑:这与@Fe
问题内容: 在休眠状态下,我可以执行以下操作 现在,如果我想获取int和String怎么办? 现在列表的结构是什么? 问题答案: 这可以。您唯一需要了解的是它将返回如下列表: