0

I am having this issue with JPA in my application. I have a parent entity Artist with one-to-one/many etch relations to other entities which I have all set to be lazily fetched. I fetch these entities using join queries. This all seems to work fine but sometimes i get a LazyInitializationException. I am using Stateless EJB's with JPA in the backend and Spring MVC in the web layer. Here is the method:

public Artist getArtistWithChildren(long id, boolean isFetchReviews, boolean isFetchRequests, boolean isFetchGigs, boolean isFetchVenues) {
    StringBuilder sql = new StringBuilder();
    sql.append("select a from Artist a join fetch a.members mrs");
    if(isFetchReviews) {
        sql.append(" left join a.reviews rvs");
    } if(isFetchRequests) {
        sql.append(" left join a.requests rqs");
    } if(isFetchGigs) {
        sql.append(" left join a.gigs gs");
    } if(isFetchVenues) {
        sql.append(" left join a.venues vs");
    }

    sql.append(" where a.id=:id");

    TypedQuery<Artist> query = em.createQuery(sql.toString(), Artist.class);
    query.setParameter("id", id);
    query.setMaxResults(1);
    List<Artist> resultList = query.getResultList();
    return resultList.get(0);
}

And here is the entity class Artist

@Entity
@Table(name="ARTIST")
public class Artist extends DescribingEntity {

private static final long serialVersionUID = -7264327449601568983L;

@ManyToMany(mappedBy="artists", targetEntity=Member.class, fetch=FetchType.LAZY, cascade={MERGE, REFRESH})
private List<Member> members;

@OneToMany(mappedBy="artist", targetEntity=VenueReview.class, fetch=FetchType.LAZY, cascade={MERGE, REFRESH, REMOVE})
private List<VenueReview> reviews;

@OneToMany(mappedBy="artist", targetEntity=Gig.class, fetch=FetchType.LAZY, cascade={MERGE, REFRESH, REMOVE})
private List<Gig> gigs;

@OneToMany(mappedBy="artist", targetEntity=GigRequest.class, fetch=FetchType.LAZY, cascade={MERGE, REFRESH, REMOVE})
private List<GigRequest> requests;

@ManyToMany(cascade={MERGE, REFRESH}, fetch=FetchType.LAZY)
@JoinTable(name="VENUE_ARTIST_REL", 
    joinColumns=@JoinColumn(name="ARTIST_ID", referencedColumnName="ARTIST_ID"), 
    inverseJoinColumns=@JoinColumn(name="VENUE_ID", referencedColumnName="VENUE_ID"))
private List<Venue> venues;

getters and setters...

I then go into debug mode to find out what went wrong and as I am stepping through the method it returns no error and no exception is thrown. Could it be that the collection is returned too soon so that all data from the DB has not had the time to populate correctly? I am a newbie when it comes to JPA so please let me know what I did wrong. Here is an example. I am using left joins here since I dont HAVE to get the results, but I doo need an instantiated collection.

I have tested the same thing using Arquillian and no errors, I also have similar methods for other entities where the scenario is the same, simply running it causes the error while step-through debugging don't.

Using Hibernate.initialize(Object o) on the child collections works fine but to my knowledge it is not a good thing to do since I then have to make a DB query for each child (correct me if I'm wrong).

I added a pastebin link to the stack trace

Stack Trace

2 Answers 2

1

In General, LazyInitializationException happens when you're lazy loading on a collection and trying to access that collection with out having a Session that encloses the context (method essentially) in which you're trying to access the lazy collection. It would be much more helpful, if you can post your error stack trace to get an exact resolution to your problem

Sign up to request clarification or add additional context in comments.

8 Comments

I added the stack trace as a link.
Without a Session, not without Transaction. E.g. detached entities
My bad, yes without a Session. Thanks for correcting me.
I am able to see the following message: "could not initialize proxy - no Session". As I mentioned earlier, this problem is because you're trying to access the lazy loaded collection, but the Session on which the collection was loaded is already closed. Also, I can see from the stack trace, that you are using Spring as your application framework. If such is the case, try using @Transactional annotation on the method where you're accessing the lazy loaded collection.
Not really. If i understood your problem correctly, you have JSP view in to which you're passing the object obtained from your EJB layer and that is the point when your lazy collection is accessed. If yes, I'd say, try to access that in an early stage(a method which is bound within you Session's context), iterate through your collection, and set it into a different object (a DTO perhaps) that your ModelAndView returns to the JSP view. Word of caution: if you're planning to use OSIV, you have the risk of facing hibernate's N+1 problem which could increase view load time.
|
1

Here is the cause explain:

The problem

A common issue in a typical (web-)application is the rendering of the view, after the main logic of the action has been completed, and therefore, the Hibernate Session has already been closed and the database transaction has ended. If you access detached objects that have been loaded in the Session inside your JSP (or any other view rendering mechanism), you might hit an unloaded collection or a proxy that isn't initialized. The exception you get is: LazyInitializationException: Session has been closed (or a very similar message). Of course, this is to be expected, after all you already ended your unit of work.

And a solution is call Open Session in View pattern. with spring based application, you can use org.springframework.orm.hibernate5.support.OpenSessionInViewInterceptor or org.springframework.orm.hibernate5.support.OpenSessionInViewFilter, but you cann't use both in one project indeed.

But for some reasion, it is treated as an antipattern:

** Reference: **

Open Session in View

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.