7

I am using Hibernate 4.2, and i have a parent entity which contains a collections of child entities (One-To-Many ,fetch type is LAZY and annotated with @BatchSize(size=100)).

If i query and load few parent entities and call access that collection which contains child object, hibernate uses the @BatchSize as the expected. But if i call session, flush and then do the same thing, it initializes collection only for that particular parent entity.

Is it the Hibernate expected behavior?

Edit: sample

    List parents = criteria.list()
    parents.get(0).getXs().get(0) // triggers loading Xs of all parents 
    

vs

    List parents = criteria.list()
    session.flush()
    parents.get(0).getXs().get(0) // triggers loading Xs of only the first parent
    
hunter
  • 3,963
  • 1
  • 16
  • 19

2 Answers2

3

I am going to answer my own question because i think this would help others. I think this is the Hibernate behavior even though it is not mentioned in any document. when we call Session.flush , it calls to the Flushing event listener and and i found this code in AbstractFlushingEventListenrner class

// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Post-flushing section
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

/**
 * 1. Recreate the collection key -> collection map
 * 2. rebuild the collection entries
 * 3. call Interceptor.postFlush()
 */
protected void postFlush(SessionImplementor session) throws HibernateException {

    LOG.trace( "Post flush" );

    final PersistenceContext persistenceContext = session.getPersistenceContext();
    persistenceContext.getCollectionsByKey().clear();

    // the database has changed now, so the subselect results need to be invalidated
    // the batch fetching queues should also be cleared - especially the collection batch fetching one
    persistenceContext.getBatchFetchQueue().clear();

So this last line clears the BatchFetchQueue for the current context

hunter
  • 3,963
  • 1
  • 16
  • 19
  • I spent 2 days on that one. Except that my flush was called implicitly by my ejb boundary. Thanks for the research, – Franck Mar 21 '16 at 18:56
1

So if I get your question correctly you do the following (pseudo code)

a = loadSomeEntity
b = loadSomeEntity
a.getXs.get(0) // triggers loading of Xs for a and b

vs

b = loadSomeEntity
session.flush
a = loadSomeEntity
a.getXs.get(0) // triggers loading only of Xs for a

This is strange to me, but if you do a session.commit or session.clear instead of the flush, it would be expected, because now b is no longer part of the session and therefor it is no candidate for batch fetching.

Jens Schauder
  • 77,657
  • 34
  • 181
  • 348
  • yes , but more accurately i use criteria.list , that means loading a and b is in a single line, then if i do a session.flush then batchsize doesn't work. – hunter Jul 31 '15 at 12:38