【发布时间】:2022-06-10 17:45:59
【问题描述】:
最近我发现在 jpa/hibernate 中使用 'select new/constructor expression' 时没有明显的行为。它对结果集中每一行中的每个实体使用一种延迟加载,效率不高。
测试示例
@Value
public class PojoTuple {
Entity1 e1;
Entity2 e2;
}
@Entity
@Table(name = "entity1", schema = DEFAULT_DATABASE_SCHEMA)
@NoArgsConstructor(access = PROTECTED)
public class Entity1 {
@Id
@Column(name = "id", nullable = false)
private String id;
@Column(name = "field1", nullable = false)
private String field1;
}
@Entity
@Table(name = "entity2", schema = DEFAULT_DATABASE_SCHEMA)
@NoArgsConstructor(access = PROTECTED)
public class Entity2 {
@Id
@Column(name = "id", nullable = false)
private String id;
@Column(name = "fkentity1", nullable = false)
private String entity1Id;
@Column(name = "field2", nullable = false)
private String field2;
}
create table entity1
(
id varchar2(22 char) not null primary key,
field1 varchar2(50 char) not null
);
create table entity2
(
id varchar2(22 char) not null primary key,
fkentity1 varchar2(22 char) not null,
field2 varchar2(50 char) not null
);
insert into entity1 (id, field1) values ('10', 'anyvalue1');
insert into entity1 (id, field1) values ('11', 'anyvalue2');
insert into entity2 (id, fkentity1, field2) VALUES ('20', '10', 'anyvalue3');
insert into entity2 (id, fkentity1, field2) VALUES ('21', '11', 'anyvalue4');
第一种情况
我们使用 select new 技术发出查询:
Query query = entityManager.createQuery("select new my.package.PojoTuple(e1, e2) " +
"from Entity1 e1 " +
"join Entity2 e2 on e1.id=e2.entity1Id ");
query.getResultList();
这会发出一个查询以获取 仅 ids 的 e1 和 e2,然后更多查询以按 id 为结果集中的每一行一个接一个地获取 e1、e2:
查询:["选择 entity1x0_.id 作为 col_0_0_,entity2x1_.id 作为 col_1_0_ 从 schema.entity1 entity1x0_ 内部连接 schema.entity2 entity2x1_ on (entity1x0_.id=entity2x1_.fkentity1)"]
查询:[“选择 entity1x0_.id 作为 id1_1_0_, entity1x0_.field1 作为 field2_1_0_ 来自 schema.entity1 entity1x0_ where entity1x0_.id=?"] 参数:[(10)]
查询:[“选择 entity2x0_.id 作为 id1_2_0_, entity2x0_.fkentity1 作为 fkentity2_2_0_,entity2x0_.field2 作为来自 schema.entity2 的 field3_2_0_ entity2x0_ where entity2x0_.id=?"] 参数:[(20)]
查询:[“选择 entity1x0_.id 作为 id1_1_0_, entity1x0_.field1 作为 field2_1_0_ 来自 schema.entity1 entity1x0_ where entity1x0_.id=?"] 参数:[(11)]
查询:[“选择 entity2x0_.id 作为 id1_2_0_, entity2x0_.fkentity1 作为 fkentity2_2_0_,entity2x0_.field2 作为来自 schema.entity2 的 field3_2_0_ entity2x0_ where entity2x0_.id=?"] 参数:[(21)]
第二种情况
而将上面的示例重写为:
Query query = entityManager.createQuery("select e1, e2 " +
"from Entity1 e1 " +
"join Entity2 e2 on e1.id=e2.entity1Id ");
query.getResultList();
仅向数据库发出一个查询,并选择所有必填字段:
查询:["选择 entity1x0_.id 作为 id1_1_0_,entity2x1_.id 作为 id1_2_1_, entity1x0_.field1 作为 field2_1_0_,entity2x1_.fkentity1 作为 fkentity2_2_1_,entity2x1_.field2 作为来自 schema.entity1 的 field3_2_1_ entity1x0_ 内部连接 schema.entity2 entity2x1_ on (entity1x0_.id=entity2x1_.fkentity1)"] 参数:[()]
问题
在我看来,这两个查询的执行方式没有太大区别。第一种情况会发出许多我不认为效率非常低的查询。第二种情况按预期工作,向数据库发出一个查询。这是一个错误、次优解决方案还是一些我看不到的隐藏功能?
环境 休眠核心:5.6.9.Final
【问题讨论】:
标签: java hibernate jpa orm jpql