Hibernate n+1 selects and lazy loading vs eager

Assuming a shop can have many products we want to display shops along with products:
1) with one select query using join – we need to annotate in @OneToMany fetchType to EAGER to produce:

this_.id as id1_1_1_,
this_.shipment_address as shipment2_1_1_,
products2_.shop_id as shop_id4_0_3_,
products2_.id as id1_0_3_,
products2_.id as id1_0_0_,
products2_.name as name2_0_0_,
products2_.price as price3_0_0_,
products2_.shop_id as shop_id4_0_0_
Shop this_
left outer join
Product products2_
on this_.id=products2_.shop_id

when calling

            Session session = sessionFactory.openSession();
            Criteria criteria = session.createCriteria(Shop.class).setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY);
            List list = criteria.list();

2) when we set fetch type to LAZY (default) then we get one select for shops and optionally additional selects for products for particular shop(s):

this_.id as id1_1_0_,
this_.shipment_address as shipment2_1_0_
Shop this_

when retrieving shops
and when we want to retrieve products for particular shop(s)

            Shop shop = shops.get(0);
            List products = shop.getProducts();

then we get:

products0_.shop_id as shop_id4_0_0_,
products0_.id as id1_0_0_,
products0_.id as id1_0_1_,
products0_.name as name2_0_1_,
products0_.price as price3_0_1_,
products0_.shop_id as shop_id4_0_1_
Product products0_

for code

public class Shop extends BaseEntity {

    @Column(name = "shipment_address", nullable = false)
    private String shipmentAddress;

    @OneToMany(mappedBy = "shop", fetch = FetchType.LAZY, cascade = CascadeType.ALL)
    private List products = new ArrayList<>();

    Shop() {
        // default constructor needed for ORM

    public Shop(String shipmentAddress, Product... products) {
        this.shipmentAddress = shipmentAddress;
        for (Product product : products) {

    public List getProducts() {
        return products;

    public String toString() {
        return "Shop{" +
                super.toString() +
                ", shipmentAddress='" + shipmentAddress + '\'' +
                //", products=" + products +

public class Product extends BaseEntity {

    private String name;

    private BigDecimal price;

    @JoinColumn(name = "shop_id", foreignKey = @ForeignKey(name = "fk_product_shop"))
    private Shop shop;

    Product() {
        // default constructor needed for ORM

    public Product(String name, BigDecimal price) {
        this.name = name;
        this.price = price;

    void addShop(Shop shop) {
        this.shop = shop;

    public String toString() {
        return "Product{" +
                super.toString() +
                ", name='" + name + '\'' +
                ", price=" + price +
                ", shop.id=" + shop.getId() + '}';


Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )


Connecting to %s