Eager fetch 在休眠中执行左连接,但在 springboot/JPA 中触发单独的 sql 查询
Eager fetch performs left join in hibernate but fires seperate sql queries in springboot/JPA
我看到很多帖子,其中 Eager fetch 在休眠中执行子 table 父 table 的左连接。但是当我使用 springboot 时,hibernate 会触发单独的 sql 查询 - 意味着一个 select 父查询 table 和一个 select 子 table 查询。为什么会有差异? springboot 有没有升级,还是我做错了什么?
以下是我正在使用的实体:
订单实体:
@Entity
@Table(name="Ordertable", schema="cf_2583f365_c3c6_499a_a60d_138e7e7023eb")
public class Order {
@Id
@Column(name = "ORDER_ID")
@GeneratedValue(strategy=GenerationType.IDENTITY)
private int orderId;
@Column(name = "DAT_SRC_ID")
private String dataSourceId;
@ManyToOne(fetch=FetchType.EAGER)
@JoinColumn(name = "ORDER_CUSTOMER_ID", referencedColumnName = "CUSTOMER_ID")
private Customer customer;
}
客户实体:
@Entity
@Table(name="Customer", schema="cf_2583f365_c3c6_499a_a60d_138e7e7023eb")
public class Customer {
@Id
@Column(name = "CUSTOMER_ID")
@GeneratedValue(strategy=GenerationType.IDENTITY)
private Long customerId;
@Column(name = "CUSTOMER_NAME")
private String customer_name;
@Column(name = "CUSTOMER_address_id")
private int customer_address_id;
@Column(name = "DAT_SRC_ID")
private String dataSourceId;
@OneToMany(fetch=FetchType.EAGER)
@JoinColumn(name = "ORDER_CUSTOMER_ID", referencedColumnName = "CUSTOMER_ID")
private List<Order> order;
}
控制器:
@RequestMapping(value="/getByCustid/{id}", method=RequestMethod.GET,produces=MediaType.APPLICATION_JSON_VALUE)
public Customer getByCustid (@PathVariable Long id) {
Customer s1 = customerRepository.findByCustomerId(id);
return s1;
}
存储库:
public interface CustomerRepository extends JpaRepository<Customer,Long> {
public Customer findByCustomerId(Long customerId);
}
以下是正在执行的查询:
select
customer0_.CUSTOMER_ID as CUSTOMER1_0_,
customer0_.CUSTOMER_address_id as CUSTOMER2_0_,
customer0_.CUSTOMER_NAME as CUSTOMER3_0_,
customer0_.DAT_SRC_ID as DAT_SRC_4_0_
from
Customer customer0_
where
customer0_.CUSTOMER_ID=?
select
order0_.ORDER_CUSTOMER_ID as ORDER_CU3_5_0_,
order0_.ORDER_ID as ORDER_ID1_5_0_,
order0_.ORDER_ID as ORDER_ID1_5_1_,
order0_.ORDER_CUSTOMER_ID as ORDER_CU3_5_1_,
order0_.DAT_SRC_ID as DAT_SRC_2_5_1_
from
Ordertable order0_
where
order0_.ORDER_CUSTOMER_ID=?
编辑:这是否与@Fetch(FetchMode.JOIN)有关——Link:JPA eager fetch does not join
为了检查 FetchMode.JOIN 是否有效,我在实体中添加了 FetchMode.JOIN,如下所示,但加入查询仍然没有成功:
客户实体:
@Entity
@Table(name="Customer", schema="cf_2583f365_c3c6_499a_a60d_138e7e7023eb")
public class Customer {
@OneToMany(fetch=FetchType.EAGER)
@JoinColumn(name = "ORDER_CUSTOMER_ID", referencedColumnName = "CUSTOMER_ID")
@Fetch(FetchMode.JOIN)
private List<Order> order;
}
订单实体:
@Entity
@Table(name="Ordertable", schema="cf_2583f365_c3c6_499a_a60d_138e7e7023eb")
public class Order {
@JsonIgnore
@ManyToOne()
@JoinColumn(name = "ORDER_CUSTOMER_ID", referencedColumnName = "CUSTOMER_ID")
@Fetch(FetchMode.JOIN)
private Customer customer;
}
findByCustomerId
实际上会根据该方法生成查询,而不是使用 em.find
。它将创建类似于 SELECT c FROM Customer c WHERE c.customerId=:customerId
的内容。之后它会注意到获取策略并获取所需的引用。这个也有解释here。查询将完全按照您的指示执行。
如果您想预先加载参考,您需要自己按照 SELECT c FROM Customer c JOIN FETCH c.orders o WHERE c.customerId=:customerId
行编写查询,这将自动检索订单。
然而 customerId
实际上是您实体的主键或标识符,因此您实际上应该使用 findById
或 findOne
方法(取决于您的 Spring 数据 JPA 版本)。这将使用 EntityManager.find
,它应该考虑映射信息并创建适当的查询。
我看到很多帖子,其中 Eager fetch 在休眠中执行子 table 父 table 的左连接。但是当我使用 springboot 时,hibernate 会触发单独的 sql 查询 - 意味着一个 select 父查询 table 和一个 select 子 table 查询。为什么会有差异? springboot 有没有升级,还是我做错了什么?
以下是我正在使用的实体:
订单实体:
@Entity
@Table(name="Ordertable", schema="cf_2583f365_c3c6_499a_a60d_138e7e7023eb")
public class Order {
@Id
@Column(name = "ORDER_ID")
@GeneratedValue(strategy=GenerationType.IDENTITY)
private int orderId;
@Column(name = "DAT_SRC_ID")
private String dataSourceId;
@ManyToOne(fetch=FetchType.EAGER)
@JoinColumn(name = "ORDER_CUSTOMER_ID", referencedColumnName = "CUSTOMER_ID")
private Customer customer;
}
客户实体:
@Entity
@Table(name="Customer", schema="cf_2583f365_c3c6_499a_a60d_138e7e7023eb")
public class Customer {
@Id
@Column(name = "CUSTOMER_ID")
@GeneratedValue(strategy=GenerationType.IDENTITY)
private Long customerId;
@Column(name = "CUSTOMER_NAME")
private String customer_name;
@Column(name = "CUSTOMER_address_id")
private int customer_address_id;
@Column(name = "DAT_SRC_ID")
private String dataSourceId;
@OneToMany(fetch=FetchType.EAGER)
@JoinColumn(name = "ORDER_CUSTOMER_ID", referencedColumnName = "CUSTOMER_ID")
private List<Order> order;
}
控制器:
@RequestMapping(value="/getByCustid/{id}", method=RequestMethod.GET,produces=MediaType.APPLICATION_JSON_VALUE)
public Customer getByCustid (@PathVariable Long id) {
Customer s1 = customerRepository.findByCustomerId(id);
return s1;
}
存储库:
public interface CustomerRepository extends JpaRepository<Customer,Long> {
public Customer findByCustomerId(Long customerId);
}
以下是正在执行的查询:
select
customer0_.CUSTOMER_ID as CUSTOMER1_0_,
customer0_.CUSTOMER_address_id as CUSTOMER2_0_,
customer0_.CUSTOMER_NAME as CUSTOMER3_0_,
customer0_.DAT_SRC_ID as DAT_SRC_4_0_
from
Customer customer0_
where
customer0_.CUSTOMER_ID=?
select
order0_.ORDER_CUSTOMER_ID as ORDER_CU3_5_0_,
order0_.ORDER_ID as ORDER_ID1_5_0_,
order0_.ORDER_ID as ORDER_ID1_5_1_,
order0_.ORDER_CUSTOMER_ID as ORDER_CU3_5_1_,
order0_.DAT_SRC_ID as DAT_SRC_2_5_1_
from
Ordertable order0_
where
order0_.ORDER_CUSTOMER_ID=?
编辑:这是否与@Fetch(FetchMode.JOIN)有关——Link:JPA eager fetch does not join
为了检查 FetchMode.JOIN 是否有效,我在实体中添加了 FetchMode.JOIN,如下所示,但加入查询仍然没有成功:
客户实体:
@Entity
@Table(name="Customer", schema="cf_2583f365_c3c6_499a_a60d_138e7e7023eb")
public class Customer {
@OneToMany(fetch=FetchType.EAGER)
@JoinColumn(name = "ORDER_CUSTOMER_ID", referencedColumnName = "CUSTOMER_ID")
@Fetch(FetchMode.JOIN)
private List<Order> order;
}
订单实体:
@Entity
@Table(name="Ordertable", schema="cf_2583f365_c3c6_499a_a60d_138e7e7023eb")
public class Order {
@JsonIgnore
@ManyToOne()
@JoinColumn(name = "ORDER_CUSTOMER_ID", referencedColumnName = "CUSTOMER_ID")
@Fetch(FetchMode.JOIN)
private Customer customer;
}
findByCustomerId
实际上会根据该方法生成查询,而不是使用 em.find
。它将创建类似于 SELECT c FROM Customer c WHERE c.customerId=:customerId
的内容。之后它会注意到获取策略并获取所需的引用。这个也有解释here。查询将完全按照您的指示执行。
如果您想预先加载参考,您需要自己按照 SELECT c FROM Customer c JOIN FETCH c.orders o WHERE c.customerId=:customerId
行编写查询,这将自动检索订单。
然而 customerId
实际上是您实体的主键或标识符,因此您实际上应该使用 findById
或 findOne
方法(取决于您的 Spring 数据 JPA 版本)。这将使用 EntityManager.find
,它应该考虑映射信息并创建适当的查询。