【问题标题】:Hibernate doing Multiple Queries when JOIN FETCH is used with reference column other than primary ID当 JOIN FETCH 与主 ID 以外的参考列一起使用时,休眠执行多个查询
【发布时间】:2020-09-28 14:02:46
【问题描述】:

我有以下问题。

每当使用 JOIN FETCH 子句通过查询调用我的存储库时,Hibernate 都会生成一个根本不需要的附加查询。这里的主要问题是,通过相应的数据库结构,两个实体(对应于两个单独的表)应该通过一个列不同而不是两个实体的 ID(即“customerid”在实体 Order 中由 @JoinColumn(name = "customerid", referencedColumnName = "customerid")") 表示。

存储库如下:

public interface CustomerRepository extends CrudRepository<Customer, Long>{

    Customer findByMsisdn(String msisdn);

    @Query("SELECT c FROM Customer c JOIN FETCH c.orders WHERE c.msisdn =:msisdn")
    Customer getCustomersAndOrdersByMsisdn(@Param("msisdn") String msisdn);
}

每当我调用 getCustomersAndOrdersByMsisdn 方法时,都会生成以下两个查询(当然我们希望只生成 Query 1):

--Query1
select
   customer0_.id as id1_0_0_,
   orders1_.id as id1_1_1_,
   customer0_.customerid as customer2_0_0_,
   customer0_.msisdn as msisdn3_0_0_,
   customer0_.status as status4_0_0_,
   orders1_.customerid as customer4_1_1_,
   orders1_.orderid as orderid2_1_1_,
   orders1_.orderstatus as ordersta3_1_1_,
   orders1_.customerid as customer4_1_0__,
   orders1_.id as id1_1_0__ 
from
   customers customer0_ 
   inner join
      orders orders1_ 
      on customer0_.customerid = orders1_.customerid 
where
   customer0_.msisdn =?

--Query2
select
      customer0_.id as id1_0_0_,
      customer0_.customerid as customer2_0_0_,
      customer0_.msisdn as msisdn3_0_0_,
      customer0_.status as status4_0_0_ 
   from
      customers customer0_ 
   where
      customer0_.customerid =?

我的两个实体(为了清楚起见,我在这里省略了 getter 和 setter,这些当然存在于我的代码中)是:

@Entity
@Table(name = "customers")
public class Customer implements Serializable {
    static final long serialVersionUID = 1L;

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private long id;


    @Column(name = "msisdn")
    private String msisdn;

    @Column(name = "status")
    private String status;

    @Column(name = "customerid", unique = true)
    @NaturalId
    private String customerid;

    @OneToMany(mappedBy = "customer", cascade = CascadeType.ALL,fetch = FetchType.LAZY)
    private Set<Order> orders;

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Customer customer = (Customer) o;
        return id == customer.id &&
                msisdn.equals(customer.msisdn) &&
                customerid.equals(customer.customerid);
    }

    @Override
    public int hashCode() {
        return Objects.hash(id, msisdn, customerid);
    }
}

@Entity
@Table(name = "orders")
public class Order implements Serializable {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private long id;

    @Column(name = "orderid")
    private int orderid;

    @Column(name = "orderstatus")
    private String orderstatus;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "customerid", referencedColumnName = "customerid")
    private Customer customer;


    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Order orders = (Order) o;
        return id == orders.id &&
                orderid == orders.orderid;
    }

    @Override
    public int hashCode() {
        return Objects.hash(id, orderid);
    }
}

【问题讨论】:

    标签: java hibernate jpa fetch hql


    【解决方案1】:

    这是绝对正常的,因为连接是使用自然 id 而不是实体的 id 进行的。 Hibernate 使用实体的 id 对实体执行操作,而不是定义的自然 id。

    所以在进行连接时,hibernate 需要获取具有自然 id 的 Customer 的实体。

    欲了解更多信息,请阅读文章@NaturalId – A good way to persist natural IDs with Hibernate?

    【讨论】:

      猜你喜欢
      • 2018-01-31
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-01-27
      • 1970-01-01
      • 2018-05-06
      • 1970-01-01
      相关资源
      最近更新 更多