Java 懒散初始化异常

Java 懒散初始化异常,java,spring,hibernate,Java,Spring,Hibernate,我得到一个例外: 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(Abstract

我得到一个例外:

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)
...
这是我的密码:

@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 );
    }
}
我做错了什么

更新

调试sessionFactory.getCurrentSession()会导致:

DEBUG : com.example.model.ArticleDAO - SessionImpl(PersistenceContext[entityKeys=[],collectionKeys=[]];ActionQueue[insertions=[] updates=[] deletions=[] collectionCreations=[] collectionRemovals=[] collectionUpdates=[] unresolvedInsertDependencies=UnresolvedEntityInsertActions[]])
我添加了一些全局变量,可能是这导致了错误?在我的控制器中有一种方法:

@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() );
}
最后我得到了我不需要的复制品

更新3

正在尝试
Hibernate.initialize()
我遇到了以下异常:

@ManyToMany( fetch = FetchType.EAGER, cascade = { CascadeType.ALL } )
org.springframework.web.util.NestedServletException: Request processing failed; nested exception is org.hibernate.LazyInitializationException: could not initialize proxy - no Session
更新4

我通过以下方式更改了获取方法:

@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();
}
这不是一个解决方案,但由于我不能处理这个问题,我将暂时使用它

我已经尝试过了(如前所述),但没有成功(它将ELException从类型上读取'id'的
错误更改为类型上读取'title'的
错误…
-可能我用错了?)


仍然需要一个解决方案

不确定出了什么问题,但有一些问题可以指导您-
1.你能调试这个方法吗

public Article get( int id )
看看你能得到什么

sessionFactory.getCurrentSession()
这是有效的会话吗


2.你能详细介绍一下文章的内容吗?是否与另一个实体存在某种关系

我怀疑你的问题在我的问题之间



根据您提供的信息更新我的答案-

正如我所怀疑的,您的文章实体与其他实体有关系
您不执行文章和相关实体的即时抓取
但是,您确实尝试修改与项目关联的集合。这是错误的
据我所知,如果您初始化了此映射(通过专门分配推动映射接口的对象,并将其设置为字段),您应该可以修改集合(在您的情况下为映射)
(您没有-Hibernate在从DB检索文章后为您初始化它,请阅读更多内容),
或者,如果已获取集合,则应修改该集合

请阅读这里有关获取的内容
您还可以编写一个HSQL,它将在没有注释的情况下执行即时获取

阅读如何使用HQL(搜索左连接获取)执行获取

不确定出了什么问题,但有一些问题可以指导您-
1.你能调试这个方法吗

public Article get( int id )
看看你能得到什么

sessionFactory.getCurrentSession()
这是有效的会话吗


2.你能详细介绍一下文章的内容吗?是否与另一个实体存在某种关系

我怀疑你的问题在我的问题之间



根据您提供的信息更新我的答案-

正如我所怀疑的,您的文章实体与其他实体有关系
您不执行文章和相关实体的即时抓取
但是,您确实尝试修改与项目关联的集合。这是错误的
据我所知,如果您初始化了此映射(通过专门分配推动映射接口的对象,并将其设置为字段),您应该可以修改集合(在您的情况下为映射)
(您没有-Hibernate在从DB检索文章后为您初始化它,请阅读更多内容),
或者,如果已获取集合,则应修改该集合

请阅读这里有关获取的内容
您还可以编写一个HSQL,它将在没有注释的情况下执行即时获取

阅读如何使用HQL(搜索左连接获取)执行获取

因为您使用的是Hibernate,所以可以调用
Hibernate.initialize()
来初始化该惰性集合


另一方面,您可以创建一个NamedQuery,用于获取与您的文章关联的所有项目并替换该集合。但是,只有当您的集合没有使用
orphanRemoving=true
注释时,才可以使用此选项。请注意,如果不小心管理实体,可能会导致数据库中出现不一致的条目。

因为您使用的是Hibernate,所以可以调用
Hibernate.initialize()
来初始化该惰性集合

另一方面,您可以创建一个NamedQuery,用于获取与您的文章关联的所有项目并替换该集合。但是,只有当您的集合没有使用
orphanRemoving=true
注释时,才可以使用此选项。要小心,因为如果不小心管理实体,数据库中可能会出现不一致的条目。

这就成功了

更改了ArticleDAO.get from

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

这就成功了

更改了ArticleDAO.get from

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

@Override
public Article get( int id )
{
    return ( Article ) sessionFactory.getCurrentSession().load( Article.class, id );
}
@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;
}