Eager fetch performs left join in hibernate but fi

2020-04-18 06:34发布

问题:

I see a lot of posts where Eager fetch performs left join of child table parent table in hibernate. But when I use springboot , hibernate fires seperate sql queries - means one select query for parent table and one select query for child table. Why is there a difference? Has there been any upgrades in springboot or is it something I am doing wrong ?

Below are the entities I am using:

Order Entity:

@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;
}

Customer Entity:

@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;

}

Controller:

@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;
}

Repository:

public interface CustomerRepository extends JpaRepository<Customer,Long> {

    public Customer findByCustomerId(Long customerId); 

}

Below are the queries that are getting executed:

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=?

EDIT : is this related to @Fetch(FetchMode.JOIN) -- Link:JPA eager fetch does not join

Hibernate: Multiple select queries made by Hibernate for Fetch mode Eager

To check whether FetchMode.JOIN works, I have added FetchMode.JOIN in entities as shown below but still no success with Join Query:

Customer Entity:

@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;
}

Order Entity:

@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;
}

回答1:

The findByCustomerId will actually generate a query based on that method instead of using em.find. It will create something along the lines of SELECT c FROM Customer c WHERE c.customerId=:customerId. afterwards it will notice the fetch strategy and obtain the needed references. This is also explained here. The query will do exactlly what you instruct it to do.

If you want to eagerly load the reference you would need to write the query yourself along the lines of SELECT c FROM Customer c JOIN FETCH c.orders o WHERE c.customerId=:customerId, this will automatically retrieve the orders.

However the customerId is actually the primary key or identitifier for your entity and thus you should actually be using the findById or findOne method (depending on your Spring Data JPA version). This will use the EntityManager.find which should take the mapping information into account and create the appropriate query.