LazyInitializationExceptionLazyInitializationException

I'm getting this exceptions:

javax.el.ELException: Error reading 'id' on type com.example.model.Article_$$_javassist_2
...

org.hibernate.LazyInitializationException: could not initialize proxy - no Session
org.hibernate.proxy.AbstractLazyInitializer.initialize(AbstractLazyInitializer.java:149)
org.hibernate.proxy.AbstractLazyInitializer.getImplementation(AbstractLazyInitializer.java:195)
org.hibernate.proxy.pojo.javassist.JavassistLazyInitializer.invoke(JavassistLazyInitializer.java:185)
com.example.model.Article_$$_javassist_2.getId(Article_$$_javassist_2.java)
...

Aquí está mi código:

@Entity
@Table( name = "tbl_articles" )
public class Article implements Comparable<Article>, Serializable
{
    private static final long serialVersionUID = 1L;

    @Id
    @Column( nullable = false )
    @GeneratedValue( strategy = GenerationType.IDENTITY )
    private Integer id;

    // some other fields

    @ManyToMany( cascade = { CascadeType.ALL } )
    @JoinTable( name = "tbl_articles_categories",
        joinColumns = { @JoinColumn( name = "article_id" ) },
        inverseJoinColumns = { @JoinColumn( name = "category_id" ) })
    @ForeignKey( name = "tbl_articles_categories_fkey_article",
        inverseName = "tbl_articles_categories_fkey_category" )
    private Set<Category> categories = new HashSet<Category>();

    @ManyToMany( cascade = { CascadeType.ALL } )
    @JoinTable( name = "tbl_articles_tags",
        joinColumns = { @JoinColumn( name = "article_id" ) },
        inverseJoinColumns = { @JoinColumn( name = "tag_id" ) })
    @ForeignKey( name = "tbl_articles_tags_fkey_article",
        inverseName = "tbl_articles_tags_fkey_tag" )
    private Set<Tag> tags = new HashSet<Tag>();

    // getters and setters
}

public abstract class BaseService<E, D extends BaseDAO<E>>
{
    protected D dao;

    public BaseService()
    {
    }

    protected D getDao()
    {
        return dao;
    }

    @Autowired
    protected void setDAO( D dao )
    {
        this.dao = dao;
    }

    @Transactional
    public E get( int id )
    {
        return dao.get( id );
    }
}

@Service
public class ArticleService extends BaseService<Article, ArticleDAO>
{
    public ArticleService()
    {
        setDAO( dao );
    }
}

public abstract class BaseDAO<E>
{
    public abstract E get( int id );
}

@Repository
public class ArticleDAO extends BaseDAO<Article>
{
    @Autowired
    private SessionFactory sessionFactory;

    @Override
    public Article get( int id )
    {
        return ( Article ) sessionFactory.getCurrentSession().load( Article.class, id );
    }
}

In my Controller now, I'm using this to get a specific article:

@RequestMapping( "/{id}/{title}.html" )
public String article( @PathVariable( "id" ) Integer id, Map<String, Object> map )
{
    map.put( "article", articleService.get( id ) );
    return "article";
}

Which I'm using in my JSP just like this:

<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>
<%@ taglib prefix="slg" uri="http://github.com/slugify" %>
<article>
    <c:url value="/blog/${article.id}/${slg:slugify(article.title)}.html" var="articleUrl" />
    <h2><a href="${articleUrl}">${article.title}</a></h2>
    <span><fmt:formatDate value="${article.creationDate}" pattern="E, dd MMM yyyy" /></span>
    <p>
        ${article.text}
    </p>
</article>

Here's my hibernate configuration as well:

# Properties file with Hibernate Settings.

#-------------------------------------------------------------------------------
# Common Settings

hibernate.generate_statistics=false
#hibernate.hbm2ddl.auto=update
hibernate.show_sql=false

#-------------------------------------------------------------------------------
# DB specific Settings

# Property that determines which Hibernate dialect to use
hibernate.dialect=org.hibernate.dialect.PostgreSQLDialect

¿Qué estoy haciendo mal?

ACTUALIZACIÓN

Depuración sessionFactory.getCurrentSession() resulta en:

DEBUG : com.example.model.ArticleDAO - SessionImpl(PersistenceContext[entityKeys=[],collectionKeys=[]];ActionQueue[insertions=[] updates=[] deletions=[] collectionCreations=[] collectionRemovals=[] collectionUpdates=[] unresolvedInsertDependencies=UnresolvedEntityInsertActions[]])

I'm adding some global variables, maybe this causing the errors? In my controller there's a method:

@ModelAttribute
public void addGlobalObjects( Map<String, Object> map )
{
    map.put( "section", "blog" );

    SortedMap<Category, Integer> categories = new TreeMap<Category, Integer>();
    for ( Category category : categoryService.list() )
    {
        categories.put( category, articleService.size( category ) );
    }

    Calendar cal = Calendar.getInstance();
    cal.set( Calendar.DAY_OF_MONTH, 1 );

    cal.add( Calendar.MONTH, ARCHIVE_MONTHS * -1 );

    SortedMap<Date, Integer> archive = new TreeMap<Date, Integer>();
    for ( int i = 0; i < ARCHIVE_MONTHS; ++i )
    {
        cal.add( Calendar.MONTH, 1 );
        archive.put( cal.getTime(), articleService.size( cal ) );
    }

    SortedMap<Tag, Integer> tags = new TreeMap<Tag, Integer>();
    for ( Tag tag : tagService.list() )
    {
        tags.put( tag, articleService.size( tag ) );
    }

    map.put( "categories", categories );
    map.put( "archive", archive );
    map.put( "tags", tags );

    map.put( "categoriesSize", categoryService.size() );
    map.put( "tagsSize", tagService.size() );

    map.put( "date", new Date() );
}

For updated article entity see above.

ACTUALIZAR2

Eager fetching didn't solved the problem - still the same exception:

@ManyToMany( fetch = FetchType.EAGER, cascade = { CascadeType.ALL } )

And finally I'm getting duplicated articles what I don't need...

ACTUALIZAR3

Molesto Hibernate.initialize() Recibo esta excepción:

org.springframework.web.util.NestedServletException: Request processing failed; nested exception is org.hibernate.LazyInitializationException: could not initialize proxy - no Session

ACTUALIZAR4

I changed my get method this way:

@Override
public Article get( int id )
{
    // return ( Article ) sessionFactory.getCurrentSession().load( Article.class, id );
    return ( Article ) sessionFactory.getCurrentSession().createCriteria( Article.class ).add( Restrictions.eq( "id", id ) ).uniqueResult();
}

This is NOT a solution, but as I can't handle this problem I'll use this temporarily.

I already tried this (as mentioned aquí) without success (it changed the ELException from Error reading 'id' on type ... a Error reading 'title' on type ... - maybe i used it wrong?):

@Override
public Article get( int id )
{
    Article ret = ( Article ) sessionFactory.getCurrentSession().load( Article.class, id );
    sessionFactory.getCurrentSession().update( ret );
    return ret;
}

A solution is still needed!

preguntado el 29 de julio de 12 a las 21:07

3 Respuestas

¡Esto funcionó!

Changed ArticleDAO.get from

@Override
public Article get( int id )
{
    return ( Article ) sessionFactory.getCurrentSession().load( Article.class, id );
}

a

@Override
public Article get( int id )
{
    Article ret = ( Article ) sessionFactory.getCurrentSession().get( Article.class, id );
    if ( ret == null )
    {
        ret = ( Article ) sessionFactory.getCurrentSession().load( Article.class, id );
    }

    return ret;
}

Respondido 02 ago 12, 00:08

Not sure what's wrong but some questions to guide you -
1. Can you debug the method

public Article get( int id )

And see what do you get for

sessionFactory.getCurrentSession()

Is this a valid session?


2. Can you elaborate more on the Article entity? is there some sort of relation to another entity?

I suspect your issues lies somewhere between my questions.



Update to my answer, following the information your provided -

As I suspected, your Article entity has relation with other entities.
You do not perform eager fetching of Article and the related entities.
However, you do try to modify the collection associated with Article. This is wrong
As far as I know, you should can modify the collection (the map in your case) either if you initialized this map (by specifically allocating an object that impelements the Map interface, and set it to the field)
(which you didn't - Hibernate initialized it for you once you retrieved an article from the DB, see more by reading about PersistentMap),
or you should modify the collection if it was fetched.

Please read here about ansioso atractivo.
You can also write an HSQL which will perform the eager fetch, without an annotation.
Lee aquí how to perform fetching using HQL (search for left join fetch).

contestado el 23 de mayo de 17 a las 12:05

Since you're using Hibernate you can invoke Hibernate.initialize() to initialize that lazy collection.

On the other hand, you can create a NamedQuery that fetches all the items that are associated to your Article and replacing that collection. However, this option is only possible if you don't have your collection annotated with orphanRemoval=true. Watch out, since you can end up having inconsistent entries in your database if you don't manage your entities with care.

Respondido 30 Jul 12, 21:07

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.