java - Hibernate:如何编写包括多级的联接查询?
问题描述
我正在尝试编写一个类似于 MySQL Join 的 HQL 查询。以下是我的实体。正如你在下面看到的,我没有在我的 Pojos 中使用注释。相反,我使用 XML 来进行映射。
库存
public class Stock implements java.io.Serializable {
private Integer idstock;
@JsonIgnoreProperties({"hibernateLazyInitializer", "handler"})
private Product product;
private int quantity;
private Date dateCreated;
private Date lastUpdated;
public Stock() {
}
public Stock(Product product, int quantity) {
this.product = product;
this.quantity = quantity;
}
public Stock(Product product, int quantity, Date dateCreated, Date lastUpdated) {
this.product = product;
this.quantity = quantity;
this.dateCreated = dateCreated;
this.lastUpdated = lastUpdated;
}
public Integer getIdstock() {
return this.idstock;
}
public void setIdstock(Integer idstock) {
this.idstock = idstock;
}
public Product getProduct() {
return this.product;
}
public void setProduct(Product product) {
this.product = product;
}
public int getQuantity() {
return this.quantity;
}
public void setQuantity(int quantity) {
this.quantity = quantity;
}
public Date getDateCreated() {
return this.dateCreated;
}
public void setDateCreated(Date dateCreated) {
this.dateCreated = dateCreated;
}
public Date getLastUpdated() {
return this.lastUpdated;
}
public void setLastUpdated(Date lastUpdated) {
this.lastUpdated = lastUpdated;
}
}
产品
public class Product implements java.io.Serializable {
private Integer idproduct;
@JsonIgnoreProperties({"hibernateLazyInitializer", "handler"})
private SparePart sparePart;
@JsonIgnoreProperties({"hibernateLazyInitializer", "handler"})
private VehicleModel vehicleModel;
private double unitPrice;
private String qrcode;
private boolean enable;
private Integer minimumStockLevel;
private Integer stockReorderLevel;
public Product() {
}
public Product(SparePart sparePart, VehicleModel vehicleModel, double unitPrice, String qrcode, boolean enable) {
this.sparePart = sparePart;
this.vehicleModel = vehicleModel;
this.unitPrice = unitPrice;
this.qrcode = qrcode;
this.enable = enable;
}
public Product(SparePart sparePart, VehicleModel vehicleModel, double unitPrice, String qrcode, boolean enable, Integer minimumStockLevel, Integer stockReorderLevel) {
this.sparePart = sparePart;
this.vehicleModel = vehicleModel;
this.unitPrice = unitPrice;
this.qrcode = qrcode;
this.enable = enable;
this.minimumStockLevel = minimumStockLevel;
this.stockReorderLevel = stockReorderLevel;
}
public Integer getIdproduct() {
return this.idproduct;
}
public void setIdproduct(Integer idproduct) {
this.idproduct = idproduct;
}
public SparePart getSparePart() {
return this.sparePart;
}
public void setSparePart(SparePart sparePart) {
this.sparePart = sparePart;
}
public VehicleModel getVehicleModel() {
return this.vehicleModel;
}
public void setVehicleModel(VehicleModel vehicleModel) {
this.vehicleModel = vehicleModel;
}
public double getUnitPrice() {
return this.unitPrice;
}
public void setUnitPrice(double unitPrice) {
this.unitPrice = unitPrice;
}
public String getQrcode() {
return this.qrcode;
}
public void setQrcode(String qrcode) {
this.qrcode = qrcode;
}
public boolean getEnable() {
return this.enable;
}
public void setEnable(boolean enable) {
this.enable = enable;
}
public Integer getMinimumStockLevel() {
return this.minimumStockLevel;
}
public void setMinimumStockLevel(Integer minimumStockLevel) {
this.minimumStockLevel = minimumStockLevel;
}
public Integer getStockReorderLevel() {
return this.stockReorderLevel;
}
public void setStockReorderLevel(Integer stockReorderLevel) {
this.stockReorderLevel = stockReorderLevel;
}
}
车辆型号
public class VehicleModel implements java.io.Serializable {
private Integer idvehicleModel;
private String modelName;
private String code;
private boolean enable;
public VehicleModel() {
}
public VehicleModel(String modelName, boolean enable) {
this.modelName = modelName;
this.enable = enable;
}
public Integer getIdvehicleModel() {
return this.idvehicleModel;
}
public void setIdvehicleModel(Integer idvehicleModel) {
this.idvehicleModel = idvehicleModel;
}
public String getModelName() {
return this.modelName;
}
public void setModelName(String modelName) {
this.modelName = modelName;
}
public boolean getEnable() {
return this.enable;
}
public void setEnable(boolean enable) {
this.enable = enable;
}
public String getCode() {
return code;
}
public void setCode(String code) {
this.code = code;
}
}
零部件
public class SparePart implements java.io.Serializable {
private Integer idsparePart;
private String sparePartName;
private String code;
private boolean enable;
public SparePart() {
}
public SparePart(String sparePartName, boolean enable) {
this.sparePartName = sparePartName;
this.enable = enable;
}
public Integer getIdsparePart() {
return this.idsparePart;
}
public void setIdsparePart(Integer idsparePart) {
this.idsparePart = idsparePart;
}
public String getSparePartName() {
return this.sparePartName;
}
public void setSparePartName(String sparePartName) {
this.sparePartName = sparePartName;
}
public boolean getEnable() {
return this.enable;
}
public void setEnable(boolean enable) {
this.enable = enable;
}
public String getCode() {
return code;
}
public void setCode(String code) {
this.code = code;
}
}
这是我的 XML 映射
产品.hbm.xml
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<!-- Generated Sep 4, 2020 1:35:36 PM by Hibernate Tools 4.3.1 -->
<hibernate-mapping>
<class name="beans.Product" table="product" catalog="aaa" optimistic-lock="version">
<id name="idproduct" type="java.lang.Integer">
<column name="idproduct" />
<generator class="identity" />
</id>
<many-to-one name="sparePart" class="beans.SparePart" fetch="select">
<column name="idspare_part" not-null="true" />
</many-to-one>
<many-to-one name="vehicleModel" class="beans.VehicleModel" fetch="select">
<column name="idvehicle_model" not-null="true" />
</many-to-one>
<property name="unitPrice" type="double">
<column name="unit_price" precision="22" scale="0" not-null="true">
<comment>This is the central price for a product. This can change according to the market values.</comment>
</column>
</property>
<property name="qrcode" type="string">
<column name="qrcode" length="45" not-null="true" />
</property>
<property name="enable" type="boolean">
<column name="enable" not-null="true" />
</property>
<property name="minimumStockLevel" type="java.lang.Integer">
<column name="minimum_stock_level" />
</property>
<property name="stockReorderLevel" type="java.lang.Integer">
<column name="stock_reorder_level" />
</property>
</class>
</hibernate-mapping>
Stock.hbm.xml
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<!-- Generated Sep 4, 2020 1:35:36 PM by Hibernate Tools 4.3.1 -->
<hibernate-mapping>
<class name="beans.Stock" table="stock" catalog="aaa" optimistic-lock="version">
<id name="idstock" type="java.lang.Integer">
<column name="idstock" />
<generator class="identity" />
</id>
<many-to-one name="product" class="beans.Product" fetch="select">
<column name="idproduct" not-null="true" />
</many-to-one>
<property name="quantity" type="int">
<column name="quantity" not-null="true" />
</property>
<property name="dateCreated" type="timestamp">
<column name="date_created" length="0" />
</property>
<property name="lastUpdated" type="timestamp">
<column name="last_updated" length="0" />
</property>
</class>
</hibernate-mapping>
SparePart.hbm.xml
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<!-- Generated Sep 4, 2020 1:35:36 PM by Hibernate Tools 4.3.1 -->
<hibernate-mapping>
<class name="beans.SparePart" table="spare_part" catalog="aaa" optimistic-lock="version">
<id name="idsparePart" type="java.lang.Integer">
<column name="idspare_part" />
<generator class="identity" />
</id>
<property name="sparePartName" type="string">
<column name="spare_part_name" length="100" not-null="true" />
</property>
<property name="code" type="string">
<column name="code" length="100"/>
</property>
<property name="enable" type="boolean">
<column name="enable" not-null="true" />
</property>
</class>
</hibernate-mapping>
车辆模型.hbm.xml
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<!-- Generated Sep 4, 2020 1:35:36 PM by Hibernate Tools 4.3.1 -->
<hibernate-mapping>
<class name="beans.VehicleModel" table="vehicle_model" catalog="aaa" optimistic-lock="version">
<id name="idvehicleModel" type="java.lang.Integer">
<column name="idvehicle_model" />
<generator class="identity" />
</id>
<property name="modelName" type="string">
<column name="model_name" length="100" not-null="true" />
</property>
<property name="code" type="string">
<column name="code" length="100"/>
</property>
<property name="enable" type="boolean">
<column name="enable" not-null="true" />
</property>
</class>
</hibernate-mapping>
现在我有以下查询。
public List<Stock> getAllStock(Session session) {
Query query = session.createQuery("FROM Stock s");
List<Stock> list = (List<Stock>) query.list();
return list;
}
这给了我,
Stock
Product
每个Stock
SparePart
每个Product
VehicleModel
每个Product
然而,由于著名的 n+1 问题,这非常慢。为了从每个表中获取数据,这段代码生成了一个 SQL 查询,产生了大量的 sql 查询。您拥有的数据越多,生成的查询就越多。因此,这是一个超级缓慢的过程。目前需要 40 秒。
相反,我需要编写 HQL 连接并使用单个 SQL 查询获取数据。我怎样才能做到这一点?
解决方案
您应该使用 JOIN FETCH 告诉 JPA/Hibernate 它应该加载它。
从休眠文档:
如果您忘记 JOIN FETCH 所有 EAGER 关联,Hibernate 将为每个关联发出辅助选择,这反过来又会导致 N+1 查询问题。
因此,您应该更喜欢 LAZY 关联。
select s from Stock s join fetch s.product p
join fetch p.sparePart sp
join fetch p.vehicleModel v
推荐阅读
- soap - 如何接收 JSON 并将其转换为 XML 并进行 SOAP 调用
- reactjs - 在用户在 handlesubmit 中发送 axios 发布请求后,更新我的图片路径的 useState?
- python-3.x - 我可以使用 pandas.DataFrame.apply() 一次制作多个列吗?
- r - 创建新行以绑定列
- c# - EF Core 异步客户端评估
- css - Nuxt 中每个页面的唯一背景图像
- angular - Angular Custom Pipe:解决承诺不起作用,但调用 AsyncPipe 会
- pandas - Group by 然后过滤具有条件的组
- python - 如何在谷歌 colab 中杀死僵尸 python 线程?
- sql - SQL中的xlookup函数