【问题标题】:Hibernate: How to write Join queries including multi levels?Hibernate:如何编写包括多级的联接查询?
【发布时间】:2021-10-18 13:50:22
【问题描述】:

我正在尝试编写一个类似于 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 映射

Product.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>

VehicleModel.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;
    }

这给了我,

  1. Stock
  2. Product 每个Stock
  3. SparePart 每个Product
  4. VehicleModel 每个Product

但是由于著名的 n+1 问题,这非常慢。为了从每个表中获取数据,这段代码生成了一个 SQL 查询,产生了大量的 sql 查询。您拥有的数据越多,生成的查询就越多。因此,这是一个超级缓慢的过程。目前需要 40 秒。

相反,我需要编写 HQL 连接并使用单个 SQL 查询获取数据。我该怎么做?

【问题讨论】:

  • 我在模型类上看不到任何 JPA/Hibernate 映射。
  • 那是因为他使用 XML 进行映射。那么就不需要注释了。
  • 对不起。请显示我们需要知道您如何映射关系的 XML
  • @SimonMartinelli:抱歉,我用 XML 更新了我的问题。
  • @ewramner:我用 XML 更新了我的问题

标签: java hibernate hql


【解决方案1】:

您应该使用 JOIN FETCH 告诉 JPA/Hibernate 它应该加载它。

来自 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

另请阅读文档:https://docs.jboss.org/hibernate/orm/5.5/userguide/html_single/Hibernate_User_Guide.html#best-practices-fetching-associations

【讨论】:

  • 太棒了。谢谢西蒙。
【解决方案2】:

您可以使用hibernate的标准实现并使用您可以加入的别名 下面是一些可能有帮助的参考代码

Criteria c = session.createCriteria(Stock.class, "stock");
c.createAlias("stock.product", "product");//it is like inner join
c.createAlias("product.spare_part","spare_part");
c.createAlias("product.vehicle_model","vehicle_model");
return c.list();

【讨论】:

    猜你喜欢
    • 2010-09-27
    • 2013-05-02
    • 1970-01-01
    • 1970-01-01
    • 2013-08-20
    • 2011-04-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多