Hibernate – fetching strategies examples

Hibernate has few fetching strategies to optimize the Hibernate generated select statement, so that it can be as efficient as possible. The fetching strategy is declared in the mapping relationship to define how Hibernate fetch its related collections and entities.

Fetching Strategies

There are four fetching strategies

1. fetch-“join” = Disable the lazy loading, always load all the collections and entities.
2. fetch-“select” (default) = Lazy load all the collections and entities.
3. batch-size=”N” = Fetching up to ‘N’ collections or entities, *Not record*.
4. fetch-“subselect” = Group its collection into a sub select statement.

For detail explanation, you can check on the Hibernate documentation.

Fetching strategies examples

Here’s a “one-to-many relationship” example for the fetching strategies demonstration. A stock is belong to many stock daily records.

Example to declare fetch strategies in XML file


...
<hibernate-mapping>
    <class name="com.mkyong.common.Stock" table="stock">
        <set name="stockDailyRecords"  cascade="all" inverse="true" 
            table="stock_daily_record" batch-size="10" fetch="select">
            <key>
                <column name="STOCK_ID" not-null="true" />
            </key>
            <one-to-many class="com.mkyong.common.StockDailyRecord" />
        </set>
    </class>
</hibernate-mapping>

Example to declare fetch strategies in annotation


...
@Entity
@Table(name = "stock", catalog = "mkyong")
public class Stock implements Serializable{
...
	@OneToMany(fetch = FetchType.LAZY, mappedBy = "stock")
	@Cascade(CascadeType.ALL)
	@Fetch(FetchMode.SELECT)
        @BatchSize(size = 10)
	public Set<StockDailyRecord> getStockDailyRecords() {
		return this.stockDailyRecords;
	}
...
}

Let explore how fetch strategies affect the Hibernate generated SQL statement.

1. fetch=”select” or @Fetch(FetchMode.SELECT)

This is the default fetching strategy. it enabled the lazy loading of all it’s related collections. Let see the example…


//call select from stock
Stock stock = (Stock)session.get(Stock.class, 114); 
Set sets = stock.getStockDailyRecords();
        
//call select from stock_daily_record
for ( Iterator iter = sets.iterator();iter.hasNext(); ) { 
      StockDailyRecord sdr = (StockDailyRecord) iter.next();
      System.out.println(sdr.getDailyRecordId());
      System.out.println(sdr.getDate());
}

Output


Hibernate: 
    select ...from mkyong.stock
    where stock0_.STOCK_ID=?

Hibernate: 
    select ...from mkyong.stock_daily_record
    where stockdaily0_.STOCK_ID=?

Hibernate generated two select statements

1. Select statement to retrieve the Stock records –session.get(Stock.class, 114)
2. Select its related collections – sets.iterator()

2. fetch=”join” or @Fetch(FetchMode.JOIN)

The “join” fetching strategy will disabled the lazy loading of all it’s related collections. Let see the example…


//call select from stock and stock_daily_record
Stock stock = (Stock)session.get(Stock.class, 114); 
Set sets = stock.getStockDailyRecords();

//no extra select
for ( Iterator iter = sets.iterator();iter.hasNext(); ) { 
      StockDailyRecord sdr = (StockDailyRecord) iter.next();
      System.out.println(sdr.getDailyRecordId());
      System.out.println(sdr.getDate());
}

Output


Hibernate: 
    select ...
    from
        mkyong.stock stock0_ 
    left outer join
        mkyong.stock_daily_record stockdaily1_ 
            on stock0_.STOCK_ID=stockdaily1_.STOCK_ID 
    where
        stock0_.STOCK_ID=?

Hibernate generated only one select statement, it retrieve all its related collections when the Stock is initialized. –session.get(Stock.class, 114)

1. Select statement to retrieve the Stock records and outer join its related collections.

3. batch-size=”10″ or @BatchSize(size = 10)

This ‘batch size’ fetching strategy is always misunderstanding by many Hibernate developers. Let see the *misunderstand* concept here…


Stock stock = (Stock)session.get(Stock.class, 114); 
Set sets = stock.getStockDailyRecords();
        
for ( Iterator iter = sets.iterator();iter.hasNext(); ) { 
      StockDailyRecord sdr = (StockDailyRecord) iter.next();
      System.out.println(sdr.getDailyRecordId());
      System.out.println(sdr.getDate());
}

What is your expected result, is this per-fetch 10 records from collection? See the output
Output


Hibernate: 
    select ...from mkyong.stock
    where stock0_.STOCK_ID=?

Hibernate: 
    select ...from mkyong.stock_daily_record
    where stockdaily0_.STOCK_ID=?

The batch-size did nothing here, it is not how batch-size work. See this statement.

The batch-size fetching strategy is not define how many records inside in the collections are loaded. Instead, it defines how many collections should be loaded.

— Repeat N times until you remember this statement —

Another example

Let see another example, you want to print out all the stock records and its related stock daily records (collections) one by one.


List<Stock> list = session.createQuery("from Stock").list();

for(Stock stock : list){
        	
    Set sets = stock.getStockDailyRecords();
            
    for ( Iterator iter = sets.iterator();iter.hasNext(); ) { 
            StockDailyRecord sdr = (StockDailyRecord) iter.next();
            System.out.println(sdr.getDailyRecordId());
            System.out.println(sdr.getDate());
    }
}
No batch-size fetching strategy

Output


Hibernate: 
    select ...
    from mkyong.stock stock0_

Hibernate: 
    select ...
    from mkyong.stock_daily_record stockdaily0_ 
    where stockdaily0_.STOCK_ID=?

Hibernate: 
    select ...
    from mkyong.stock_daily_record stockdaily0_ 
    where stockdaily0_.STOCK_ID=?

Keep repeat the select statements....depend how many stock records in your table.

If you have 20 stock records in the database, the Hibernate’s default fetching strategies will generate 20+1 select statements and hit the database.

1. Select statement to retrieve all the Stock records.
2. Select its related collection
3. Select its related collection
4. Select its related collection
….
21. Select its related collection

The generated queries are not efficient and caused a serious performance issue.

Enabled the batch-size=’10’ fetching strategy

Let see another example with batch-size=’10’ is enabled.
Output


Hibernate: 
    select ...
    from mkyong.stock stock0_

Hibernate: 
    select ...
    from mkyong.stock_daily_record stockdaily0_ 
    where
        stockdaily0_.STOCK_ID in (
            ?, ?, ?, ?, ?, ?, ?, ?, ?, ?
        )

Now, Hibernate will per-fetch the collections, with a select *in* statement. If you have 20 stock records, it will generate 3 select statements.

1. Select statement to retrieve all the Stock records.
2. Select In statement to per-fetch its related collections (10 collections a time)
3. Select In statement to per-fetch its related collections (next 10 collections a time)

With batch-size enabled, it simplify the select statements from 21 select statements to 3 select statements.

4. fetch=”subselect” or @Fetch(FetchMode.SUBSELECT)

This fetching strategy is enable all its related collection in a sub select statement. Let see the same query again..


List<Stock> list = session.createQuery("from Stock").list();

for(Stock stock : list){
        	
    Set sets = stock.getStockDailyRecords();
            
    for ( Iterator iter = sets.iterator();iter.hasNext(); ) { 
            StockDailyRecord sdr = (StockDailyRecord) iter.next();
            System.out.println(sdr.getDailyRecordId());
            System.out.println(sdr.getDate());
    }
}

Output


Hibernate: 
    select ...
    from mkyong.stock stock0_

Hibernate: 
    select ...
    from
        mkyong.stock_daily_record stockdaily0_ 
    where
        stockdaily0_.STOCK_ID in (
            select
                stock0_.STOCK_ID 
            from
                mkyong.stock stock0_
        )

With “subselect” enabled, it will create two select statements.

1. Select statement to retrieve all the Stock records.
2. Select all its related collections in a sub select query.

Conclusion

The fetching strategies are highly flexible and a very important tweak to optimize the Hibernate query, but if you used it in a wrong place, it will be a total disaster.

Reference

1. http://docs.jboss.org/hibernate/core/3.3/reference/en/html/performance.html
2. https://www.hibernate.org/315.html

About the Author

author image
mkyong
Founder of Mkyong.com, love Java and open source stuff. Follow him on Twitter, or befriend him on Facebook or Google Plus. If you like my tutorials, consider make a donation to these charities.

Comments

Leave a Reply

avatar
newest oldest most voted
Kisna
Guest
Kisna

There needs some mentioning about the duplicates that result in different types of collection fetching, for example

@Fetch(FetchMode.SUBSELECT) and SELECT will eliminate duplicates whereas join (which is optimal) does not, you end up using distinct then.

himanshu prasad
Guest
himanshu prasad

nice explanation.

sk
Guest
sk

very simple explanation, you are helping me a lot, thanks

Tim Bain
Guest
Tim Bain
Your explanation of JOIN and SELECT semantics is pretty misleading, since the concept of fetch mode is orthogonal to whether you’re eagerly or lazily loading an associated collection. SELECT fetch semantics can be used for either eager or lazy loading (though JOIN can only be used for eager loading), so a better statement of your first two bullets would be: 1. fetch-“join” = Load all the collections and entities in the same query as the parent entity. Note that this can only be used with eager loading. 2. fetch-“select” (default) = Load all the collections and entities in a separate… Read more »
Vaibhav
Guest
Vaibhav

Thanks. The article is really helpful indeed. Helped me to reduce the number of selects hibernate was performing for joins.

Alexandr Melnichnikov
Guest
Alexandr Melnichnikov

Thank u, my friend that u and your site exists!! It’s very,very,very usefull. For my russian mind that’s the best explanation.

Timon
Guest
Timon

Hello, it would be very helpfull to compare what would happen in each strategies if we want to retrieve all stocks. However its really great exmplanation

Alen Jain
Guest
Alen Jain

hat’s off to you. Specially for demonstrating whats wrong is done by programmers and just after that how it is done in correct manner..

Anand
Guest
Anand

I used this

@OneToMany(.. fetch=FetchType.LAZY)
@Fetch(FetchMode.JOIN)

I found that, because of FetchMode.JOIN, only one query is fired to load the data and LAZY loading is of no effect here even though I have used it using FetchType.LAZY.

Could you please explain me this behavior?

Aravind
Guest
Aravind

A very nice post. But I’m still trying to make it work.
I’m trying to use @Fetch(FetchMode.SUBSELECT) on OneToMany mapped set collection. But when I run a test program it still generates many queries. What could be the reason?

trackback
hibernate-lazy-loading-eager-loading | mauroprogram's Blog
Jitendra
Guest
Jitendra

Nice Explanation.

I have a question here with some different situation here.

Suppose i a have parent object/entity as a Stock and its child collection as a StockDailyRecord. In StockDailyRecord i have a property like activeRecord (Value could be Y/N). Now i want to perform an eager loading for parent.child collection’s which are active(setted Y).

Stock.StockDailyRecord.activeRecord = ‘Y’.

krishna
Guest
krishna

Sorry, I forget to add how I am mapping..

I am doing one-to-many mapping by using fetching strategy as “select” and I got the following error while trying to get the mapped object.

org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: could not initialize proxy – no Session

krishna
Guest
krishna

I am using this but lazy load is not working. Do I need to do any more configurations to make lazy load workable.?

Thanks,
Krishna

Diyyana Kishore Babu
Guest
Diyyana Kishore Babu

@ Diyyana Kishore Babu.
Really very good explanation, but one small correction for ?fetch=?select?? strategy.
You mentioned as
?Hibernate generated two select statements
1. Select statement to retrieve the Stock records -session.get(Stock.class, 114)
2. Select its related collections ? sets.iterator()?.

Actually it generate 1(stock) + n(stock_daily_record) for select fetch.

Let?s say stock_daily_record have 10 records it generate 10 select statements and one select statement for stock table.

So Hibernate generate 11 (1+10) select statements for ?select? fetch strategy.

Diyyana Kishore Babu
Guest
Diyyana Kishore Babu

Really very good explanation, but one small correction for ?fetch=?select?? strategy.
You mentioned as
?Hibernate generated two select statements
1. Select statement to retrieve the Stock records -session.get(Stock.class, 114)
2. Select its related collections ? sets.iterator()?.

Actually it generate 1(stock) + n(stock_daily_record) for select fetch.

Let?s say stock_daily_record have 10 records it generate 10 select statements and one select statement for stock table.

So Hibernate generate 11 (1+10) select statements for ‘select’ fetch strategy.

geelong
Guest
geelong

how to define how many records inside in the collections are loaded.

Maharsh
Guest
Maharsh

Excellent explanation of fetching strategy with wonderful example !! Thanks.

prashanth
Guest
prashanth

very nice examples easy to understand……..

Manish
Guest
Manish

Thanks Mkyong for posting very nice article and in a simple way also!!

What is difference between lazy=true and fetch=select as both are responsible to trigger lazy initialization for associated collection.

SIddhant
Guest
SIddhant

What is meaning of FetchMode.LAZY and FetchMode.EAGER ..?

mperk
Guest
mperk

I try this example. But I have error
Exception in thread “main” org.hibernate.LazyInitializationException: could not initialize proxy – no Session

Cristian Ortiz
Guest
Cristian Ortiz

Hey Guys there is a possible of doing a OneToMany relationship using criteria and pagination methods(setMaxResult and setFirstResult) and completely LAZY loading the Many relationship[IS Loaded Eagerly on Annotations] thanks a lot.

amit
Guest
amit

very nice article.
Thanks for posting this one.

Thanks,
Amit

Anon
Guest
Anon

“The fetching strategies are highly flexible and a very important tweak to optimize the Hibernate query, but if you used it in a wrong place, it will be a total disaster.”

— why are we all dancing around “disaster” again? We all know how JDBC is going to behave. Is it really that hard to read a result set or use a JdbcTemplate or something simple like iBatis? What does hibernate give us that justifies flirting with disaster?

belatrix
Guest
belatrix

great article, I only have single doubt , how to restrict elements in collections directly on query level ? because the fetchmode=join causes all elements in collection to be fetched and if I apply a Restrictions on associated entities’ properties, It gives me, property not found exception

Vijay
Guest
Vijay

I have no words to thank you! Just the explanation I was looking for. Great work ..Kudos to you!

Suresh Siva
Guest
Suresh Siva

Very sharp and crisp explanation…very neat….Thanks…

Adarsh
Guest
Adarsh

It was very helpful.
Got exactly what i was looking for. GREAT

HibLearner
Guest
HibLearner
Suppose I have an Order table with 50 columns and I have an Order class with 50 properties and mapped with each other in hibernate file. I just want to show order list to the user which may have at most 3 to 4 columns like order_id, date, placed_by and order_amount. My problem starts here… when I load rows through the class, all 50 columns will be loaded along with the required just 4 columns which may impact the performance significantly. And sometime I want to load one (1) order with say 20 columns and sometime want to load a… Read more »
bekbote
Guest
bekbote
 I have tried this scenario with Criteria.setProjection(Projections.property(...))