Pages

Monday, September 20, 2010

Hibernate's Open Session in View in Spring MVC

Problem: org.hibernate.LazyInitializationException on web application view rendering. 

Recipe:
LazyInitializationException is one of the most common Hibernate exception's that appears during web development.
It appears when hibernate tries to access persistent object without assocciated hibernate session.

For example assume Spring MVC controller:

@RequestMapping(value = "/users/{id}")
    public ModelAndView getUserInfo(@PathElement("id") String id, Model model) {
        
        //get user from database
        User user = userService.findUser(id);
    
        model.addAttribute("user", user);
        return new ModelAndView("userInfoView");
    }
}
and hibernate persistent class:
package uk.lmoren.blog.demo;

import java.io.Serializable;
import java.util.List;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.OneToMany;
import javax.persistence.Table;

/**
 * @author Lukasz Moren
 */

@Entity
@Table
public class User implements Serializable {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column
    private Long id;

    @Column
    private String name;

    @OneToMany(cascade = CascadeType.ALL, mappedBy = "user", fetch = FetchType.LAZY)
    private List albums;
    
    // access method ommited
    // ... ...    

}

Spring controller intercept request that matches pattern: /users/{user}, fetch user object with given id from database, add it to the application model and redirect to view named: userUnfoView. The View retrieves an information from model and display it to the user.

Example .jsp (using JSTL tags) page doing that:
Username:${user.name}

User albums:

    Album name: ${album.name} 



When server try to read list of albums through ${user.albums} will cause org.hibernate.LazyInitializationException. The problem is that there is no associated hibernate session with thread fetching abums from database. It is great explained in post: http://community.jboss.org/docs/DOC-13954

Simply solution for that is just start new hibernate session and database transaction with every HTTP request and commit it just before sending response. It assures that view is fully rendered before closing session and there is no open database connection left.

Spring comes up with implementation of that either through:
org.springframework.orm.hibernate3.support.OpenSessionInViewInterceptor
or
org.springframework.orm.hibernate3.support.OpenSessionInViewFilter
Both behave similarly, difference is explained here: opensessioninviewinterceptor-vs-opensessioninviewfilter/.



To configure OpenSessionInViewFilter filter add to web.xml filter configuration and url mapping:
    
        hibernateSessionInViewFilter
        org.springframework.orm.hibernate3.support.OpenSessionInViewFilter
    

    
        hibernateSessionInViewFilter
        /a/*
    

Similarly with OpenSessionInViewInterceptor , add this to Spring's applicationContext.xml configuration file:


    
        
           
            
                
           
           
        
    


Now you can forget about LazyInitializationException. Hope it helps.

3 comments:

  1. how did you define sessionFactory? Thanks!

    ReplyDelete
    Replies
    1. Hi RC,

      Just traditional way for Spring-Hibernate, e.g.:
      http://pastebin.com/e5YDuQPF

      Cheers, Lukasz

      Delete