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

2022-09-03 00:17:01

我正在使用JPA(与Hibernate 4.3.3作为持久性提供者)沿着Spring(3.2.2),我的所有字段都加载正常,但是当我尝试访问我的收藏时,它会抛出错误 -

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)

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

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

 @PersistenceContext(type=PersistenceContextType.EXTENDED)

        protected EntityManager em;

这工作正常,但通过这个我发现em将永远保持开放,现在春天不会处理这个问题。有没有办法使用Spring解决这个问题。任何帮助都非常感谢。

我的实体是 -

  @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();

}

我的 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>  

毅力.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>

这是我的道,我正在通过服务层调用道

@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);
    }


}

服务层

    @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);
    }

}

这是主要的

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
    }
    }

答案 1

问题是,当此方法调用返回时:

Category parentCategory=serviceCategory.findCategoryById(2l);

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

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

解决方案是从事务上下文调用 ,这永远不可能是应用程序的主要方法。parentCategory.getAllParentCategoryrefs()

然后将父类别重新附加到新的持久性上下文,然后调用 getter。

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

serviceCategory.nowItWorks(parentCategory);

其中,服务上的方法为事务性:

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

在DAO中:

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

答案 2

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

Category parentCategory=serviceCategory.findCategoryById(2l);

从 Hibernate 文档中回想一下,延迟加载仅在休眠会话中起作用(在本例中,休眠会话以服务调用开始和结束)。您无法(仅)重新连接到休眠会话来初始化集合。

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


推荐