org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: pojo.Person.address, no session or session was closed.
I am getting this exception and I'm using Spring 3.0 and Hibernate 3.6.
It looks like you have an Entity called Person which has a lazily loaded mapped collection of Addresses? You have loaded the Person and the session it was loaded in has now been closed.
After the session was closed you then attempted to access that collection of address and Hibernate attempted to load them. However, that is not possible if the original session is no longer available.
In order to access the address property you have a few options:
Use the OpenSessionInView pattern to ensure that the Hibernate session is held open for the duration of the request/response cycle (Since you've tagged Spring MVC I'll assume this is a web based operation). This essentially scopes your Hibernate session to the HTTP request.
Ensure that all required properties are loaded before the session is closed (transaction committed). You can do this using
Hibernate.initialize(person.address)
or by writing HQL that uses a left join fetch. This could be something like:
createQuery("from Person as person left join fetch person.address")
This will override any lazy loading configuration for this query only and ensure that any collections are initialized.
Most probably, you don't have transaction management set up. That is, Spring uses default transaction scope, which is transaction per HibernateTemplate call, and closes session right after return from HibernateTemplate.
You can do one of three things:
set up transactions,
switch to explicit session handling,
use Criteria API or fetch join in order to prefetch the details you need.
I was seeing this issue because I had failed to annotate a method in a service with #Transactional. It seems that Hibernate closes the session when a call to another method is made (even within the same class) unless the caller is annotated appropriately.
Related
Following is a hypothetical situation on Spring 3.x and Hibernate3.x
I have a service layer in spring which invokes 3 DAOs to construct a model.
The DAOs are transactional(#Transactional) and have lazy loaded hibernate collections.
The service method causes a few updates ,along with the fetch of data.
A typical DAO method will be as follows -
public O create(I entity) throws GenericException {
getOrCreateSession().save(entity);
return (O)entity;
}
I have the following questions around OSIV -
1.How many times is this session flushed(database update) in the default AUTO mode?
2.Can OSIV be made to extend the session beyond a single request (to a conversation)?
The AUTO flush mode will execute the pending DML statements when:
the current transaction is committed
when a query might target an entity table, that's current enqueued for flushing
Spring Webflow has support for long conversations.
From the docs - http://docs.spring.io/spring-framework/docs/2.0.x/api/org/springframework/orm/hibernate/HibernateTransactionManager.html
HibernateTransactionManager - Binds a Hibernate Session from the specified factory to the thread, potentially allowing for one thread-bound Session per factory
OpenSessionInViewFilter - This filter makes Hibernate Sessions available via the current thread, which will be autodetected by transaction managers.
What is the difference between both of them and at what scenarios should they be used ?
OpenSessionInViewFilter
Now when you are using OpenSessionInViewFilter, by default the session's flush mode is set to NEVER. So when you try to save something in your action using hibenate and commit it, it wont be reflected in your database. To solve this you need to flush the session in your action class or extend OpenSessionInViewFilter and override closeSession(Session session, SessionFactory sessionFactory).
Now it is also possible that you are maintaining a single transaction for per request. In your action you edit the attributes of a object and update it using session.update(object). But it is not yet commited as some other processing is remaining. At the same time, some other request is invoking a action which tries to retrieve the object which you were updating. Since the object is not yet commited the other request will get the old object. To solve this you need to begin a transaction before you load object and commit the transaction after you update the object. So that as soon as the object is saved/updated it is commited. With this there can be many transaction in single user request but only one session.
The OpenSessionInView pattern only guarantees that the session is open during one single thread execution.
When the page has been rendered and has been returned to the browser, the session gets closed by the filter.
So subsequent requests (e.g. navigation request) require another new session which will be opened by the OpenSessionInViewFilter. But as the "old" person object is not connected to the "new" session, it is considered as disconnected object which's references cannot be loaded lazily.
We have a FlushEventListener to do audit functionality. While updating some entity, hibernate will callback our audit code just before flushing. The audit code needs to query the database.
If we try to do it in the same session apparently we mess up the session's state: we get a NullPointerException from inside hibernate, at some point when it's validating naturalIds inside a class named NaturalIdXrefDelegate.
We currently solved it by opening a new session for the audit query. The problem with this is we're losing the benefit of getCurrentSession (a session for the whole request, managed by hibernate). This way we're going back to opening one session per query.
Is there an elegant solution for this or we basically need to re-implement getCurrentSession to manage our own session #2 in the request?
You don't have to open new session. It's enough to temporarily disable flush.
Session session = entityManager.unwrap(Session.class);
session.setHibernateFlushMode(FlushMode.MANUAL);
// do your db stuff
session.setHibernateFlushMode(FlushMode.AUTO);
It's actually a lot faster than
session.getSessionFactory().openSession()
Which works to btw.
I've got an error that looks like this:
Could not initialize proxy - no Session
I'm working with java, hibernate and spring. This error comes up when trying to generate a PDF document, and I'm following the next steps to generate it on the fly and store in the database.
I sent a request to the app through a POST method. This generates the PDF on the fly and shows to the user.
Just after that request I send another, but through an ajax a request. This will generate the same PDF but will save it in the DB.
The error shows that a query could not be executed due to "could not initialize proxy - no Session" error.
Is there something that am I doing wrong, calling the same methods twice from the same user session? Could it be that the session is closed before both requests have finished?
Hope someone can help me to understand what is happening.
Your problem is that the hibernate Session lives only for one request. It opens in the start of the request and closes at the end. You guessed the answer: Hibernate session is closed before both requests are finished.
Exactly what is happening? Your entity objects live during both requests. How? They are stored in the HTTP session (which is a different thing called session) You don't give much information about the framework you are using, so I can't give you more details, but it is certain that the framework you are using somehow keeps your entities in the HTTP session. This is how the framework makes it easy for you to work with the same objects for more than one requests.
When the processing of the second request starts, the code is trying to access some entity (usually an element of a collection) that is lazily initialized by hibernate. The entity is not attached to a hibernate session, and so hibernate can't initialize the hibernate proxy before reading it. You should open a session and re-attach your entity to it at the beginning of the ajax request processing.
EDIT:
I will try to give a brief explanation of what is happening behind the scene. All java web frameworks have one or more servlets that handle the requests. The servlet handles each request (HttpRequest) by creating a new thread that will finally produce the response (HttpResponse). The method that processes each request is executed inside this thread.
At the beginning of the request processing your application should allocate the resources that it needs for processing (Transaction, Hibernate session etc). At the end of the processing cycle these resources are released (Transaction is committed, hibernate session is closed, JDBC connections are released etc). Lifecycle of these resources could be managed by your framework, or could be done by your code.
In order to support application state in a stateless protocol as HTTP, we have the HttpSession object. We (or the frameworks) put on HttpSession the information that remains relevant between different request cycles of the same client.
During the processing of the first request hibernate reads (lazily) an entity from the database. Due to lazy initialization some parts of this object's structure are hibernate proxy objects. These objects are associated with the hibernate session that created them.
The framework finds the entity from the previous request in the HttpSession object when you try to process the second request. Then it is trying to access a property from a child entity that was lazily initialized and now is a hibernate proxy object. The hibernate proxy object is an imitation of the real object that will ask its hibernate session to fill it with information from the database when someone tries to access one of its properties. This what your hibernate proxy is trying to do. But its session was closed at the end of the previous request processing, so now it doesn't have a hibernate session to use in order to be hydrated (filled with real info).
Note that it is possible that you have already opened a hibernate session at the beginning of the second request, but it isn't aware of the entity that contains the proxy object because this entity was read by a different hibernate sesion. You should re-attach the entity to the new hibernate session.
There is a lot of discussion about how to re-attach a detached entity, but the simplest approach right now is session.update(entity).
Hope it helps.
Noticed that if I want to read some data and if I do not have a transaction context I will not be able to do so because
org.hibernate.HibernateException: No Session found for current thread
For reading data , is not required a transaction normally.
So in order for Spring to manage the session it needs to have a transaction even for read only operations like selects... ?
Is that not an overhead ?
PS.I do not want to open and close session manually...
Thanks a lot.
#Transactional tells spring to open and close a session, in addition to instructing it to start and commit a transaction. This is not very straightforward, but that's how it works. So if you don't have #Transactional, no session gets opened. Here are your options:
use #Transactional(readOnly=true) - the purpose is to have a read-only transaction. I recommend that one
use JPA EntityManager injected with #PersistenceContext. It will open a new underlying session for each invocation. Not that good option. But you should consider using EntityManager with a readOnly=true transaction
Use an additional aspect/interceptor/filter to open and close session. That would be hard, and you may end up confused by the spring implementation of hibernate's current session concept.