February 17, 2010

Spring Hibernate - LazyInitializationException

« Configuring Beans in the Spring IoC Container | Main | Native Maven Plugin - Build native C/C++ projects with Maven »
Let's assume you want to map a one-to-many relation using hibernate. In this case we have a Person with a list of i.e. Attributes. An Attribute is stored in one table and we use one table to store the relations between a person and his attributes. Since a Person could have multiple attributes we use a combined primary key consiting of person_id and attribute_id.
To represent this relation in Hibernate we insert into Person a List of Attribute and annotate the getter as shown here:
 
@Entity
@Table(name = "person") 
class Person{

  private Long id;
  [...]
  private List attributes;

  @OneToMany(fetch = FetchType.LAZY)
  @JoinColumn(name="person_id")
  List getAttributes(){
     return this.attributes;
  }
}
Attribute itself is not shown here because we are only interested in the id of the Attribute and the value "attributeComment" of the relationship between Person and Attribute. The relationship called AttributeMatrix is shown here:
@Entity
@Table(name = "attributematrix")
public class AttributeMatrix

   AttributeMatrixPrimaryKey attributeMatrixPK;
   String attributeComment;

   @Id
   AttributeMatrixPrimaryKey getAttributeMatrixPK(){
        return this.attributeMatrixPK;
   }
We need an extra class for the primary key because it consists of multiple columns and we do that by annotating it as @Embeddable and implementing the Serializable-Interface.
@Embeddable
public class AttributeMatrixPrimaryKey implements Serializable {

    private Long personId;
    private Long attributeId;

    @Column(name = "person_id")
    public Long getPersonId() {
        return personId;
    }

    @Column(name = "attribute_id")
    public Long getAttributeId() {
        return attributeId;
    }

}
In our persistence-layer we implement a method that delivers us an instance of the class Person by PersonId.
    public Person getPersonById(Long personId) {
        Person person = (Person)getHibernateTemplate().get(Person.class,personId);
        return person;
    }
Since we got the instance of our class Person we could perform several operations on Person like reading the name.
    /**
     * Some Javadoc
     */
    public List getPersonWithAttributes(Long personId) throws PersonServiceException {
     
     Person person = persistenceLayer.getPersonById(personId);
     if("crusoe".equals(person.getLastname()){
        System.out.println("Hooray, Mr Crusoe has been found");
     }
But in the moment we try to access the "List attributes" of the instance we got via the method above, a LazyInitializationException would occur telling us that the Hibernate session had already been closed. no session or session was closed. This is because Hibernate wants to get the AttributeMatrix as we access it and Spring closed it as we left the method getPersonById(Long personId) The solution is simple: We just annotate the method getPersonWithAttributes(Long personId) with @Transactional(propagation = Propagation.NESTED, rollbackFor = PersonServiceException.class) so that is looks like this:
    /**
     * Some Javadoc
     */
    @Transactional(propagation = Propagation.NESTED, rollbackFor = PersonServiceException.class)
    public List getPersonWithAttributes(Long personId) throws PersonServiceException {
     [....]
In this case Spring leaves the Hibernate-session open for the duration of the method getPersonWithAttributes(Long personId) and Hibernate can now lazy-fetch the list of the Attributes.

Technorati Tags:

Posted by guido.herrmann at 10:20 PM in Java

 

[Trackback URL for this entry]

Your comment:

(not displayed)
 
 
 

Live Comment Preview:

 
« February »
SunMonTueWedThuFriSat
 123456
78910111213
14151617181920
21222324252627
28