简体   繁体   中英

Hibernate Lazy Initialization Exception for loading lazy list

I have these two entities

@Entity
@Table(name = "CallSession")
public class CallSession implements Serializable {

    private long id;
    private List<CallParticipant> members;

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    public long getId() {
        return id;
    }

    public void setId(long id) {
        this.id = id;
    }    

    @OneToMany(mappedBy = "callSession", fetch = FetchType.LAZY)
    public List<CallParticipant> getMembers() {
        return members;
    }

    public void setMembers(List<CallParticipant> members) {
        this.members = members;
    }    
}    


@Entity
@Table(name = "CallParticipant")
public class CallParticipant implements Serializable {    

    private long id;
    private CallSession callSession;    

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    public long getId() {
        return id;
    }

    public void setId(long id) {
        this.id = id;
    }

    @ManyToOne
    public CallSession getCallSession() {
        return callSession;
    }

    public void setCallSession(CallSession callSession) {
        this.callSession = callSession;
    }    
}

but when I invoke callSession.getMembers() method, I get this Exception:

Unable to evaluate the expression Method threw 'org.hibernate.LazyInitializationException' exception.

I cannot make a head or tail of why I get this error? Why do I get this error and how can I fix this?

I'm going to start by assuming you want your collection to be lazy loaded.

Hibernate's session can be closed in a lot of contexts, and once the session is closed, it won't be able to fetch any lazy loaded collections.

Generally Hibernate is very good at keeping sessions open for the lifecycle of HTTP threads in a web app context (Spring's “open session in view”). Reasons the session could be closed include that the object was handed off from one thread to another, or the object was cached and then accessed by another thread.

But it can be more difficult if your code is running in a job or a non-web application context.

Fixes

1. Create a repository method to explicitly fetch the collection

Using @Query and join fetch , add a repository method that explicitly eager-loads the collection.

2. Call.toString() on the collection after fetching the object.

This is a nasty hack that I've seen many people use in the real world before. Basically, before caching the object or handing it off to an executor or somewhere where it would be accessed by another thread, call.toString() on the collection to load it. Usually leave a comment explaining why.

3. Add @Transactional to a method that is both fetching the data and accessing the collection

This has many implications other than keeping the session alive (eg database operations succeed and fail together), but can be a quick fix to keep the session alive in for example a job method.

Hope this helps.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM