-->
These old forums are deprecated now and set to read-only. We are waiting for you on our new forums!
More modern, Discourse-based and with GitHub/Google/Twitter authentication built-in.

All times are UTC - 5 hours [ DST ]



Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 2 posts ] 
Author Message
 Post subject: Batch Collection Initializing
PostPosted: Sat Mar 14, 2015 9:27 am 
Newbie

Joined: Sat Mar 14, 2015 8:54 am
Posts: 4
Hi, guys.

Please explain why Hibernate loads entities with batches of power of two elements? How it can be avoided?

To demonstrate this, I made test project with 3 entities: Owner, Car, Manufacturer.
Please see code of entities below:

Owner:
Code:
@Entity(name = "com.github.karasik.entity.IOwner")
@Table(name = "OWNER")
@AttributeOverrides(value = {@AttributeOverride(name = "name", column = @Column(name = "OWNER_NAME"))})
public class OwnerDTO extends AbstractNamedEntityDTO implements IOwner {

    private Collection<ICar> cars;

    @Id
    @Column(name = "OWN_AA")
    public Integer getIdentifier() {
        return super.getIdentifier();
    }

    @OneToMany(mappedBy = "owner", targetEntity = CarDTO.class, cascade = CascadeType.ALL)
    @Override
    public Collection<ICar> getCars() {
        return cars;
    }

    @Override
    public void setCars(Collection<ICar> cars) {
        this.cars = cars;
    }
}



Car:
Code:
@Entity(name = "com.github.karasik.ICar")
@Table(name = "CAR")
@AttributeOverrides({@AttributeOverride(name = "name", column = @Column(name = "CAR_NAME"))})
public class CarDTO extends AbstractNamedEntityDTO implements ICar {

    private IOwner owner;
    private IManufacturer manufacturer;

    @Id
    @Column(name = "CAR_AA")
    @Override
    public Integer getIdentifier() {
        return super.getIdentifier();
    }

    @Override
    @ManyToOne(targetEntity = OwnerDTO.class)
    @JoinColumn(name = "CAR_OWN_AA")
    public IOwner getOwner() {
        return owner;
    }

    @Override
    public void setOwner(IOwner owner) {
        this.owner = owner;
    }

    @ManyToOne(targetEntity = ManufacturerDTO.class)
    @JoinColumn(name = "CAR_MAN_AA")
    @Fetch(FetchMode.SELECT)
    @Override
    public IManufacturer getManufacturer() {
        return manufacturer;
    }

    @Override
    public void setManufacturer(IManufacturer manufacturer) {
        this.manufacturer = manufacturer;
    }
}



Manufacturer:
Code:
@Entity(name = "com.github.karasik.entity.IManufacturer")
@Table(name = "MANUFACTURER")
@AttributeOverrides({@AttributeOverride(name = "name", column = @Column(name = "MAN_NAME"))})
public class ManufacturerDTO extends AbstractNamedEntityDTO implements IManufacturer {

    @Id
    @Column(name = "MAN_AA")
    @Override
    public Integer getIdentifier() {
        return super.getIdentifier();
    }
}



I have this Database CAR table structure:
Code:
efim=# select * from car;
car_aa | car_name | car_man_aa | car_own_aa
--------+----------+------------+------------
      1 | Car 1    |          1 |          1
      2 | Car 2    |          2 |          1
      3 | Car 3    |          3 |          1
      4 | Car 4    |          4 |          1
      5 | Car 5    |          5 |          1
      6 | Car 6    |          6 |          1
      7 | Car 7    |          7 |          1
      8 | Car 8    |          8 |          1
      9 | Car 9    |          9 |          1
     10 | Car 10   |         10 |          1
     11 | Car 11   |         11 |          1
(11 rows)


When using Hibernate I load from DB Owner record with own_aa=1 and then initialize Cars collection:

Code:
   
public Integer getCarCount(Integer manufacturerAa) {
    IOwner owner = dao.find(OwnerDTO.class, manufacturerAa);
    return owner.getCars().size();
}


Hibernate needs to load 11 car entities.
Please note, it makes two queries to load manufacturers (Fetch=SELECT):
Code:
    select
        cars0_.CAR_OWN_AA as CAR_OWN_3_2_1_,
        cars0_.CAR_AA as CAR_AA1_0_1_,
        cars0_.CAR_AA as CAR_AA1_0_0_,
        cars0_.CAR_MAN_AA as CAR_MAN_2_0_0_,
        cars0_.CAR_OWN_AA as CAR_OWN_3_0_0_
    from
        CAR cars0_
    where
        cars0_.CAR_OWN_AA=?


    select
        manufactur0_.MAN_AA as MAN_AA1_1_0_
    from
        MANUFACTURER manufactur0_
    where
        manufactur0_.MAN_AA in (
            ?, ?, ?, ?, ?, ?, ?, ?, ?, ?
        )


    select
        manufactur0_.MAN_AA as MAN_AA1_1_0_
    from
        MANUFACTURER manufactur0_
    where
        manufactur0_.MAN_AA=?


For some reason instead of fetching 11 manufacturers via single query, Hibernate makes two queries.
From source code I can see, that loading is performed in batches of 1,2,...,10,16,32,64,128,...,hibernate.default_batch_fetch_size entities.

Could you please advice how can I change Hibernate behavior not to perform two queries for 10 and 1 element but to make single query for 11 elements?
I wonder why Hibernate fetching behavior was made this way. An explanation will be very helpful.

Sorry if this question is a duplicate or a well known Hibernate feature.
Thanks a lot!


Top
 Profile  
 
 Post subject: Re: Batch Collection Initializing
PostPosted: Tue Mar 24, 2015 3:05 pm 
Newbie

Joined: Sat Mar 14, 2015 8:54 am
Posts: 4
I found an answer for my question.
Since Hibernate 4.2 there is an ability to change Batch Fetch Style.
Please see link below.

http://docs.jboss.org/hibernate/orm/4.2/manual/en-US/html/ch20.html#performance-fetching-batch


Top
 Profile  
 
Display posts from previous:  Sort by  
Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 2 posts ] 

All times are UTC - 5 hours [ DST ]


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum

Search for:
© Copyright 2014, Red Hat Inc. All rights reserved. JBoss and Hibernate are registered trademarks and servicemarks of Red Hat, Inc.