Hibernate总是运行冗余查询
Hibernate always running redundant query
我的数据模型中有一个 OneToOne 关系,hibernate 总是查询这两个实体以生成结果集。
这是数据模型
@Entity
public class C1 {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
@OneToOne(cascade = CascadeType.ALL, fetch = FetchType.LAZY, orphanRemoval = true, optional = false, targetEntity = C2.class)
private C2 c2;
//... other stuff
}
@Entity
public class C2 extends OtherClassOutOfDomain {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
@OneToOne(fetch = FetchType.LAZY, mappedBy = "c2")
private C1 c1;
//... other stuff
}
Hibernate 将我的模式生成为两个 table,C1 table 有一个指向 C2 的外键,这对我来说是完美的,因为我会更频繁地使用 C1。
但是
每次我查询 C1 hibernate 都会生成 1 个查询,每行连接两个实体数据,并为第一个结果中的每一行生成 N 个查询(甚至在我访问结果集之前)
例子
Hibernate (just one):
select
this_.id as id1_2_1_,
this_.c2_id as authDat22_2_1_,
this_.bio as bio2_2_1_,
this_.blocked as blocked3_2_1_,
this_.commentsAmount as comments4_2_1_,
this_.confirmed as confirme5_2_1_,
this_.deleted as deleted6_2_1_,
c22_.id as id1_0_0_,
c22_.adid as adid2_0_0_,
from
c1 this_
inner join
c2 c22_
on this_.authData_id=c22_.id
Hibernate (N times as the size of previous query):
select
this_.id as id1_2_1_,
this_.c2_id as authDat22_2_1_,
this_.bio as bio2_2_1_,
this_.blocked as blocked3_2_1_,
this_.commentsAmount as comments4_2_1_,
this_.confirmed as confirme5_2_1_,
this_.deleted as deleted6_2_1_,
c22_.id as id1_0_0_,
c22_.adid as adid2_0_0_,
from
c1 this_
inner join
c2 c22_
on this_.authData_id=c22_.id
where
this_.authData_id=?
.....repeat
.....repeat
.....repeat
重复查询的结果都包含在第一个大查询的行中...有什么办法可以避免这些不必要的请求吗?我尝试设置为懒惰,但没有用
我 运行 获得此行为的代码很简单
HibernateUtils.createNewSession().createCriteria(C1.class).list();
在触发嵌套查询之前,我什至没有访问结果
我正在使用休眠 5.10 e mysql 5.7.17
我找到了解决方案,但我没有完全理解为什么。
由于映射 OneToOne 关系与 JPA hibernate 会将外键放在具有 "targetEntity" 属性的实体上(具有属性的实体没有在属性值中设置的实体)
当查询一个在其结构中有外键的实体时,hibernate 将自动查询嵌套实体(我不知道原因)
为了解决我之前的相关问题,我只需要将注释更改为
@OneToOne(cascade = CascadeType.ALL, fetch = FetchType.LAZY, orphanRemoval = true, optional = false, mappedBy= "c1")
private C2 c2;
@OneToOne(fetch = FetchType.LAZY, targetEntity = C1.class)
private C1 c1;
记住这两件事。
OneToOne 的默认抓取策略是 EAGER。
LAZY 只能在关联不可为空的 OneToOne 关联上工作。
你的问题与N+1选择问题类似
解决 N+1 SELECT 问题:
HQL 获取连接
两者都
来自
C1 C1
左连接抓取
c1.c2
或
@OneToOne(cascade = CascadeType.ALL, fetch = FetchType.LAZY, orphanRemoval = true, optional = false, mappedBy= "c1")
@Fetch(FetchMode.JOIN)
private C2 c2;
第二个 class
@OneToOne(fetch = FetchType.LAZY, mappedBy = "c2")
@Fetch(FetchMode.JOIN)
private C1 c1;
我的数据模型中有一个 OneToOne 关系,hibernate 总是查询这两个实体以生成结果集。
这是数据模型
@Entity
public class C1 {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
@OneToOne(cascade = CascadeType.ALL, fetch = FetchType.LAZY, orphanRemoval = true, optional = false, targetEntity = C2.class)
private C2 c2;
//... other stuff
}
@Entity
public class C2 extends OtherClassOutOfDomain {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
@OneToOne(fetch = FetchType.LAZY, mappedBy = "c2")
private C1 c1;
//... other stuff
}
Hibernate 将我的模式生成为两个 table,C1 table 有一个指向 C2 的外键,这对我来说是完美的,因为我会更频繁地使用 C1。
但是
每次我查询 C1 hibernate 都会生成 1 个查询,每行连接两个实体数据,并为第一个结果中的每一行生成 N 个查询(甚至在我访问结果集之前)
例子
Hibernate (just one):
select
this_.id as id1_2_1_,
this_.c2_id as authDat22_2_1_,
this_.bio as bio2_2_1_,
this_.blocked as blocked3_2_1_,
this_.commentsAmount as comments4_2_1_,
this_.confirmed as confirme5_2_1_,
this_.deleted as deleted6_2_1_,
c22_.id as id1_0_0_,
c22_.adid as adid2_0_0_,
from
c1 this_
inner join
c2 c22_
on this_.authData_id=c22_.id
Hibernate (N times as the size of previous query):
select
this_.id as id1_2_1_,
this_.c2_id as authDat22_2_1_,
this_.bio as bio2_2_1_,
this_.blocked as blocked3_2_1_,
this_.commentsAmount as comments4_2_1_,
this_.confirmed as confirme5_2_1_,
this_.deleted as deleted6_2_1_,
c22_.id as id1_0_0_,
c22_.adid as adid2_0_0_,
from
c1 this_
inner join
c2 c22_
on this_.authData_id=c22_.id
where
this_.authData_id=?
.....repeat
.....repeat
.....repeat
重复查询的结果都包含在第一个大查询的行中...有什么办法可以避免这些不必要的请求吗?我尝试设置为懒惰,但没有用
我 运行 获得此行为的代码很简单
HibernateUtils.createNewSession().createCriteria(C1.class).list();
在触发嵌套查询之前,我什至没有访问结果
我正在使用休眠 5.10 e mysql 5.7.17
我找到了解决方案,但我没有完全理解为什么。
由于映射 OneToOne 关系与 JPA hibernate 会将外键放在具有 "targetEntity" 属性的实体上(具有属性的实体没有在属性值中设置的实体)
当查询一个在其结构中有外键的实体时,hibernate 将自动查询嵌套实体(我不知道原因)
为了解决我之前的相关问题,我只需要将注释更改为
@OneToOne(cascade = CascadeType.ALL, fetch = FetchType.LAZY, orphanRemoval = true, optional = false, mappedBy= "c1")
private C2 c2;
@OneToOne(fetch = FetchType.LAZY, targetEntity = C1.class)
private C1 c1;
记住这两件事。
OneToOne 的默认抓取策略是 EAGER。
LAZY 只能在关联不可为空的 OneToOne 关联上工作。
你的问题与N+1选择问题类似
解决 N+1 SELECT 问题:
HQL 获取连接
两者都
来自 C1 C1 左连接抓取 c1.c2
或
@OneToOne(cascade = CascadeType.ALL, fetch = FetchType.LAZY, orphanRemoval = true, optional = false, mappedBy= "c1")
@Fetch(FetchMode.JOIN)
private C2 c2;
第二个 class
@OneToOne(fetch = FetchType.LAZY, mappedBy = "c2")
@Fetch(FetchMode.JOIN)
private C1 c1;