Sequence of flush(); clear(); commit(); can lead to LazyInitializationException

Description

I have a discriminator that throws a lazyloading exception in some cases:

I'm trying to isolate the condition, but I wanted to note this here.

Attachments

1

Activity

Show:

Fabio Massimo Ercoli August 13, 2019 at 9:19 AM

Hi, starting from the test you provided, I created a simple reproducer:

 

 

This test fails on the sample project.

I’m trying on Hibernate Search 6….

Yoann Rodière September 13, 2018 at 6:30 AM

Adding the full answer to this <make changes>; flush(); clear(); <repeat>; problem, since it's potentially relevant here; copy-pasted from this stackoverflow answer:

The first, perhaps more correct, solution, would be for you to not use a single, big transaction, but multiple smaller ones. For example create a transaction for each chunk of 200 elements. Of course this means if a chunk fails, the previous chunks will still be in the database, but in many cases this might not matter, as you can just restart from where you failed, and the index would still be in sync with the database.

Spring gives you control over transactions using transaction templates, so you can manually start a new transaction for each chunk of 200 elements, or just refactor your code to put the @Transactional annotation at the right place. [There should be similar features in Java EE, I just don't know about them out of the top of my head.]

The second solution would be for you to still use a single, big transaction, but during the transaction periodically flush your changes, both to the database (which would be able to rollback the changes later if the transaction is aborted, don't worry) and to the index (which would not be able to rollback the changes later). This means in particular that if the transaction fails, you would have to restart everything and purge the index, because it would not be in sync with the database (which rolled back the changes) anymore.

You can find an example using periodic flushing in the documentation: https://docs.jboss.org/hibernate/search/5.10/reference/en-US/html_single/#search-batchindex-flushtoindexes

If you adapt the example, your code will look more or less like this:

Yoann Rodière September 13, 2018 at 6:13 AM

Digging this up... The correct sequence of commands when batching works would actually be: `flush();flushToIndexes(); clear(); commit();`. This should prevent any `LazyInitializationException` from happening.

Not to say we shouldn't try to detect it automatically and trigger the `flushToIndexes` ourselves, but I thought it could help.

See also https://docs.jboss.org/hibernate/search/5.10/reference/en-US/html_single/#search-batchindex-flushtoindexes

Emmanuel Bernard January 23, 2015 at 8:09 AM

For info the sequence at bay is

We are trying to see if that sequence is common and makes sense in real life (i.e. aside from tests).

We could try and make that work but it would require to:

  • detect that a flush happens (some kind of flag that would be cleared by a search flush)

  • upon pre-clear, aggressively build the Document objects and keep them around

  • upon commit, build the remaining Documents (potential second flush) and write the old and new documents

That's a fairly heavy work. We would prefer not to have to spend that energy here if the use case is uncommon.

can you describe in more detail the use case you ahve for a em.flush(); em.clear(); commit(); sequence?

Gunnar Morling January 22, 2015 at 11:21 AM

Hi , after taking a closer look I realized the error isn't raised from within the discriminator but from your custom class bridge where you access the comments collection.

That exception actually makes sense, as you invoke EntityManager#clear() prior to accessing it from within the class bridge, which makes the Post entity unmanaged. As the comment collection hasn't been initialized before (just adding an element doesn't load the collection's state from the database) the exception is rightfully raised.

I adapted the test to actually navigate the lazy assocation from Country to Language within the discriminator and that worked as expected, i.e. the language entity is fetched from the database.

So I'm going to close this issue as "Cannot re-produce". Feel free to re-open if you have a test case which actually causes a LazyInitializationException within the discriminator (and which is not caused by manually detaching objects with unloaded lazy references). Thx!

Fixed

Details

Assignee

Reporter

Labels

Components

Fix versions

Affects versions

Priority

Created June 13, 2013 at 4:20 AM
Updated August 23, 2019 at 2:33 PM
Resolved August 20, 2019 at 3:45 PM