Java 未能懒惰地初始化角色集合,..无法初始化代理 - 没有会话 - JPA + SPRING

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/22643098/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-13 17:02:32  来源:igfitidea点击:

failed to lazily initialize a collection of role,..could not initialize proxy - no Session - JPA + SPRING

javaspringhibernatespring-mvcjpa

提问by henrycharles

I am using JPA(with Hibernate 4.3.3 as persistence provider ) along Spring (3.2.2) , all my fields are loading fine but when I am trying to access my Collection it's throwing the error-

我在 Spring (3.2.2) 中使用 JPA(使用 Hibernate 4.3.3 作为持久性提供程序),我所有的字段都加载良好,但是当我尝试访问我的 Collection 时,它抛出了错误-

Exception in thread "main" org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: com.br.common.catalog.entity.Category.allParentCategoryXrefs, could not initialize proxy - no Session
    at org.hibernate.collection.internal.AbstractPersistentCollection.throwLazyInitializationException(AbstractPersistentCollection.java:572)
    at org.hibernate.collection.internal.AbstractPersistentCollection.withTemporarySessionIfNeeded(AbstractPersistentCollection.java:212)
    at org.hibernate.collection.internal.AbstractPersistentCollection.initialize(AbstractPersistentCollection.java:551)
    at org.hibernate.collection.internal.AbstractPersistentCollection.read(AbstractPersistentCollection.java:140)
    at org.hibernate.collection.internal.PersistentBag.toString(PersistentBag.java:526)
    at java.lang.String.valueOf(String.java:2827)
    at java.io.PrintStream.println(PrintStream.java:771)
    at test.Test.main(Test.java:30)

When I debugged this I was getting error for every collection defined in my entity class - com.sun.jdi.InvocationException occurred invoking method.

当我调试这个时,我的实体类中定义的每个集合都出现错误 - com.sun.jdi.InvocationException occurred invoking method.

I tried using collection.size() and Hibernate.initialize() but none of this worked. On searching on internet I found that extending Persitence will solve the problem ie.

我尝试使用 collection.size() 和 Hibernate.initialize() 但这些都不起作用。在互联网上搜索时,我发现扩展 Persitence 将解决问题,即。

 @PersistenceContext(type=PersistenceContextType.EXTENDED)

        protected EntityManager em;

this worked fine but through this I found that em will always remain opened , now spring will not handle this. Is there any way to solve this problem using Spring. Any Help is highly appreciated.

这工作得很好,但通过这个我发现它们将始终保持打开状态,现在 spring 不会处理这个。有什么办法可以使用Spring解决这个问题。任何帮助都受到高度赞赏。

My Entities are as -

我的实体是 -

  @Entity
    @Inheritance(strategy = InheritanceType.JOINED)
    @Table(name="CATEGORY")
    public class Category implements Serializable {
       @Id
        @GeneratedValue(generator= "CategoryId")
         @Column(name = "CATEGORY_ID")
        protected Long id;

        @ManyToOne(targetEntity = Category.class)
        @JoinColumn(name = "DEFAULT_PARENT_CATEGORY_ID")
        @Index(name="CATEGORY_PARENT_INDEX", columnNames={"DEFAULT_PARENT_CATEGORY_ID"})
        protected Category defaultParentCategory;

        @OneToMany(targetEntity = Categoryref.class, mappedBy = "categoryrefPK.category")
        @Cache(usage = CacheConcurrencyStrategy.READ_WRITE, region="test")
        @OrderBy(value="displayOrder")
        @BatchSize(size = 50)

        protected List<Categoryref> childCategoryRefs = new ArrayList<Categoryref>(10);
        @OneToMany(targetEntity = Categoryref.class, mappedBy = "categoryrefPK.subCategory",fetch=FetchType.LAZY)
        @Cascade(value={org.hibernate.annotations.CascadeType.MERGE, org.hibernate.annotations.CascadeType.PERSIST})
        @OrderBy(value="displayOrder")
        @BatchSize(size = 50)
        protected List<Categoryref> parentCategoryRefs = new ArrayList<Categoryref>(10);

    }


@Entity
@Polymorphism(type = PolymorphismType.EXPLICIT)
@Inheritance(strategy = InheritanceType.JOINED)
@Table(name = "CATEGORY_REF")
public class Categoryref implements Serializable {
    /** The category id. */
    @EmbeddedId
    CategoryrefPK categoryrefPK = new CategoryrefPK();

    public CategoryrefPK getCategoryrefPK() {
        return categoryrefPK;
    }

    public void setCategoryrefPK(final CategoryrefPK categoryrefPK) {
        this.categoryrefPK = categoryrefPK;
    }
  }

@Embeddable
public class CategoryrefPK implements Serializable {

    @ManyToOne(targetEntity = Category.class, optional=false)
    @JoinColumn(name = "CATEGORY_ID")
    protected Category category = new Category();

    @ManyToOne(targetEntity = Category.class, optional=false)
    @JoinColumn(name = "SUB_CATEGORY_ID")
    protected Category subCategory = new Category();

}

My Xml Configuration is as -

我的 Xml 配置是 -

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop"
    xmlns:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
           http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
           http://www.springframework.org/schema/aop
           http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
           http://www.springframework.org/schema/context
           http://www.springframework.org/schema/context/spring-context-3.0.xsd
           http://www.springframework.org/schema/tx  
           http://www.springframework.org/schema/tx/spring-tx.xsd">

    <context:component-scan base-package="com.br" />

    <bean id="dataSource"
        class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        ....
    </bean>
<!--  this is also used we can used this also  -->
  <tx:annotation-driven transaction-manager="transactionManager" />  
    <bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
        <property name="entityManagerFactory" ref="entityManagerFactory" />
    </bean>
    <bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
        <property name="persistenceXmlLocation" value="classpath:META-INF/persistence.xml" />
        <property name="dataSource" ref="dataSource" />
         <property name="persistenceUnitName" value="abc" />   
        <property name="packagesToScan" value="com.br.common.*" />
        <property name="jpaVendorAdapter">
            <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
                <property name="showSql" value="true" />
                <property name="databasePlatform" value="org.hibernate.dialect.MySQLDialect" />
            </bean>
        </property>
    </bean>  


</beans>  

Persitence.xml

持久化文件

    <?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.0"
    xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd">
    <persistence-unit name="abc">
        transaction-type="RESOURCE_LOCAL">
          <mapping-file>META-INF/category.orm.xml</mapping-file>
        <class>com.br.common.Category</class>
        <class>com.br.common.Categoryref</class>
        <class>com.br.common.CategoryrefPK</class>

        <properties>
            <property name="javax.persistence.jdbc.user" value="user"
            <property name="javax.persistence.jdbc.driver" value="com.mysql.jdbc.Driver" />
            <property name="hibernate.dialect" value="org.hibernate.dialect.MySQLDialect"></property>
            <property name="javax.persistence.jdbc.url" value="jdbc:mysql://localhost:3306/test>
            <property name="javax.persistence.jdbc.password" value="...">
            <property name="hibernate.show_sql" value="true" />

            <property name="hibernate.transaction.flush_before_completion"
                value="false" />
            <property name="hibernate.connection.autocommit" value="true" />
            <property name="hibernate.cache.region.factory_class" value="org.hibernate.cache.ehcache.SingletonEhCacheRegionFactory"/>
            <property name="hibernate.cache.use_second_level_cache" value="true" /> 
            <property name="hibernate.cache.use_query_cache" value="true"/>
            <property name="hibernate.generate_statistics" value="false" />
            <property name="hibernate.archive.autodetection" value="false" />
            <property name="hibernate.dialect" value="org.hibernate.dialect.MySQLDialect" />
            <property name="hibernate.id.new_generator_mappings" value="true" />
        </properties>
    </persistence-unit>
</persistence>

this is my dao i am calling dao through service layer

这是我的 dao 我通过服务层调用 dao

@Repository("categoryDaoImpl")
public class CategoryDaoImpl implements ICategoryDAO {

    @PersistenceContext
    protected EntityManager em;


    public Category save(Category category) {
      Category category2=   em.merge(category);

         em.flush();
         return category2;
  }
    public Category readCategoryById(Long categoryId) {
        return em.find(Category.class, categoryId);
    }


}

servie layer

服务层

    @Service("blCatalogService")
@Transactional(propagation=Propagation.REQUIRED)
public class CatalogServiceImpl implements ICatalogService {

    @Resource(name="categoryDaoImpl")
    protected ICategoryDAO categoryDao;

    @Transactional
    public Product saveProduct(Product product) {
        return productDao.save(product);
    }

    public Category findCategoryById(Long categoryId) {
        return categoryDao.readCategoryById(categoryId);
    }

}

this is main

这是主要的

public class Test {


        public static void main(String[] args) {
                ApplicationContext context = new ClassPathXmlApplicationContext(
                    "applicationContext-persistence.xml");
            ICatalogService serviceCategory= (ICatalogService) context
                    .getBean("blCatalogService");
                Category parentCategory=serviceCategory.findCategoryById(2l);
    System.out.println(parentCategory.getAllParentCategoryrefs());//here error is coming while accessing collection
    }
    }

回答by Aaron

Like @Zeus said, this has been answered many, MANY, times before. You are having this problem in your test class because your transaction begins and ends at your service call:

就像@Zeus 所说的,这个问题之前已经被回答过很多次了。您在测试类中遇到此问题,因为您的事务在您的服务调用开始和结束:

Category parentCategory=serviceCategory.findCategoryById(2l);

Recall from Hibernate documentation that lazy loading only works within a Hibernate Session (in this case, the hibernate session begins and ends with your service call). You can't reconnect to the hibernate session (simply) to initialize the collection.

回忆一下 Hibernate 文档,延迟加载仅适用于 Hibernate 会话(在这种情况下,休眠会话以您的服务调用开始和结束)。您不能重新连接到休眠会话(简单地)来初始化集合。

I'm not exactly sure what you mean when you want to solve it "in spring." Since this isn't a Spring issue. Essentially the two ways to resolve this are to load the collection within the hibernate session you load the parent in or execute a separate fetch outside of the original hibernate session.

当您想“在春天”解决它时,我不确定您的意思。因为这不是 Spring 问题。本质上,解决此问题的两种方法是在加载父级的休眠会话中加载集合,或者在原始休眠会话之外执行单独的提取。

回答by Angular University

The problem is that when this method call returns:

问题是当这个方法调用返回时:

Category parentCategory=serviceCategory.findCategoryById(2l);

Here you are no longer in a @Transactionalcontext. this means that the session linked to parentCategory got closed. now when you try to access a collection linked to a closed session, the No Sessionerror occurs.

在这里,您不再处于@Transactional上下文中。这意味着链接到 parentCategory 的会话已关闭。现在,当您尝试访问链接到已关闭会话的集合时,No Session会发生错误。

One thing to notice is that the main method runs outside any spring bean and has no notion of persistence context.

需要注意的一件事是 main 方法在任何 spring bean 之外运行,并且没有持久化上下文的概念。

The solution is to call the parentCategory.getAllParentCategoryrefs()from a transactional context, which can never be the main method of your application.

解决方案是parentCategory.getAllParentCategoryrefs()从事务上下文中调用,它永远不会成为应用程序的主要方法。

Then reattach the parentCategory to the new persistence context, and then call the getter.

然后将 parentCategory 重新附加到新的持久化上下文,然后调用 getter。

Try for example to pass the parentCategory back to a transactional method of the same service:

例如,尝试将 parentCategory 传递回同一服务的事务方法:

serviceCategory.nowItWorks(parentCategory);

where the method on the service is transactional:

服务上的方法是事务性的:

@Transactional(readOnly=true)
public void nowItWorks(Category category) {
    dao.nowItWorks(category);
}

And in the DAO:

在 DAO 中:

public void nowItWorks(Category category) {
    Category reattached = em.merge(category);
    System.out.println("It works: " + reattached.getAllParentCategoryrefs());
}

回答by Max

Try using fetch=FetchType.EAGER, it will work

尝试使用fetch=FetchType.EAGER,它会起作用

回答by blue shadown

use @Fetch(FetchMode.SELECT)and @LazyCollection(LazyCollectionOption.FALSE)on your domain set collection , it will work

使用@Fetch(FetchMode.SELECT)@LazyCollection(LazyCollectionOption.FALSE)在您的域集集合上,它将起作用