Подтвердить что ты не робот

Не удалось лениво инициализировать коллекцию роли,.. не удалось инициализировать прокси - нет сеанса - JPA + SPRING

Я использую 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 не справится с этим. Есть ли способ решить эту проблему с помощью 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>  

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>

это мой 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

    @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
    }
    }
4b9b3361

Ответ 1

Проблема заключается в том, что при вызове этого метода:

Category parentCategory=serviceCategory.findCategoryById(2l);

Здесь вы больше не находитесь в контексте @Transactional. это означает, что сеанс, связанный с parentCategory, закрыт. теперь, когда вы пытаетесь получить доступ к коллекции, связанной с закрытым сеансом, возникает ошибка No Session.

Следует заметить, что основной метод работает вне любого spring bean и не имеет понятия контекста персистентности.

Решение состоит в вызове parentCategory.getAllParentCategoryrefs() из транзакционного контекста, который никогда не может быть основным методом вашего приложения.

Затем верните родительскую категорию в новый контекст персистентности, а затем вызовите получателя.

Попробуйте, например, передать родительскую категорию обратно транзакционному методу той же службы:

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, что ленивая загрузка работает только на сеансе Hibernate (в этом случае сеанс гибернации начинается и заканчивается вызовом службы). Вы не можете повторно подключиться к сеансу гибернации (просто), чтобы инициализировать коллекцию.

Я не совсем уверен, что вы имеете в виду, когда хотите его решить "в spring." Поскольку это не проблема Spring. По сути, два способа решить эту проблему - загрузить коллекцию в сеансе hibernate, в которую вы загружаете родительский элемент или выполняете отдельную выборку за пределами исходного сеанса спящего режима.

Ответ 3

используйте @Fetch(FetchMode.SELECT) и @LazyCollection(LazyCollectionOption.FALSE) в своей коллекции набора доменов, он будет работать

Ответ 4

Попробуйте использовать fetch=FetchType.EAGER, он будет работать