最近我發現 在 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');
第一個案例
我們使用選擇新技術發出查詢:
Query query = entityManager.createQuery("select new my.package.PojoTuple(e1, e2) "
"from Entity1 e1 "
"join Entity2 e2 on e1.id=e2.entity1Id ");
query.getResultList();
這將發出一個查詢以僅獲取e1 和 e2 的 id,然后針對結果集中的每一行按 id 逐一獲取 e1、e2 的更多查詢:
查詢:["select entity1x0_.id as col_0_0_, entity2x1_.id as col_1_0_ from schema.entity1 entity1x0_ inner join schema.entity2 entity2x1_ on (entity1x0_.id=entity2x1_.fkentity1)"]
查詢:[“select entity1x0_.id as id1_1_0_, entity1x0_.field1 as field2_1_0_ from schema.entity1 entity1x0_ where entity1x0_.id=?”] 引數:[(10)]
查詢:[“select entity2x0_.id as id1_2_0_, entity2x0_.fkentity1 as fkentity2_2_0_, entity2x0_.field2 as field3_2_0_ from schema.entity2 entity2x0_ where entity2x0_.id=?”] 引數:[(20)]
查詢:[“選擇 entity1x0_.id 作為 id1_1_0_,entity1x0_.field1 作為 field2_1_0_ from schema.entity1 entity1x0_ where entity1x0_.id=?”] 引數:[(11)]
查詢:[“select entity2x0_.id as id1_2_0_, entity2x0_.fkentity1 as fkentity2_2_0_, entity2x0_.field2 as field3_2_0_ from schema.entity2 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();
僅向資料庫發出一個查詢,并選擇所有必填欄位:
查詢:[“select entity1x0_.id as id1_1_0_, entity2x1_.id as id1_2_1_, entity1x0_.field1 as field2_1_0_, entity2x1_.fkentity1 as fkentity2_2_1_, entity2x1_.field2 as field3_2_1_ from schema.entity1 entity1x0_ inner join schema.entity2 entity2x1_ on (entity1x0_ =entity2x1_.fkentity1)"] 引數:[()]
問題
從我的角度來看,這兩個查詢的執行方式沒有太大區別。第一種情況會發出許多我不認為效率非常低的查詢。第二種情況按預期作業,向資料庫發出一個查詢。這是一個錯誤、次優解決方案還是一些我看不到的隱藏功能?
環境休眠核心:5.6.9.Final
uj5u.com熱心網友回復:
所以我終于從我所知道的關于休眠的最權威的知識來源中找到了部分解釋 - Vlad Mihalcea: Paragraph: Returning an entity in a DTO projection
但是,當您想要在 DTO 投影中選擇一個物體時,可能會有一些用例。(...)
當您執行這樣的 JPQL 查詢時:
List<PersonAndCountryDTO> personAndAddressDTOs = entityManager.createQuery( "select new " " com.vladmihalcea.book.hpjp.hibernate.query.dto.PersonAndCountryDTO(" " p, " " c.name" " ) " "from Person p " "join Country c on p.locale = c.locale " "order by p.id", PersonAndCountryDTO.class) .getResultList();Hibernate 生成以下 SQL 查詢:
SELECT p.id AS col_0_0_, c.name AS col_1_0_ FROM Person p INNER JOIN Country c ON ( p.locale = c.locale ) ORDER BY p.id SELECT p.id AS id1_1_0_, p.locale AS locale2_1_0_, p.name AS name3_1_0_ FROM Person p WHERE p.id = 3 SELECT p.id AS id1_1_0_, p.locale AS locale2_1_0_, p.name AS name3_1_0_ FROM Person p WHERE p.id = 4在不執行輔助查詢的情況下,DTO 投影的 Hibernate 5.2 實作無法從 ResultSet 實作 DTO 投影。但是,這對性能非常不利,因為它可能導致 N 1 查詢問題。
這個 HQL 限制已經討論過了,Hibernate 6.0 新的 SQM 決議器可能會解決這個問題,敬請期待!
所以總結一下:
- 我詢問的行為是休眠開發人員已知的,并且希望它會得到修復。
- 就目前而言,必須知道使用建構式運算式提取完整的托管物體作為一種設計是完全可以的,但是由于 hibernate 發出的許多查詢,使用 hibernate 5.x 可能會導致非最佳解決方案
uj5u.com熱心網友回復:
您不應在使用建構式運算式創建的物件中回傳物體。這不是此功能的目的,這也是它使用許多查詢加載資料的原因。
https://docs.jboss.org/hibernate/orm/current/userguide/html_single/Hibernate_User_Guide.html#hql-select-new
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/490060.html
