web-dev-qa-db-fra.com

n'a pas réussi à initialiser une collection de rôles paresseusement, .. n'a pas pu initialiser le proxy - pas de session - JPA + SPRING

J'utilise JPA (avec Hibernate 4.3.3 comme fournisseur de persistance) le long de Spring (3.2.2), tous mes champs se chargent correctement mais quand j'essaie d'accéder à ma collection, cela lance l'erreur-

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)

Lorsque j'ai débogué cela, j'obtenais une erreur pour chaque collection définie dans ma classe d'entité - com.Sun.jdi.InvocationException occurred invoking method.

J'ai essayé d'utiliser collection.size () et Hibernate.initialize () mais rien de tout cela n'a fonctionné. En recherchant sur Internet, j'ai trouvé que l'extension de la persistance résoudrait le problème, c'est-à-dire.

 @PersistenceContext(type=PersistenceContextType.EXTENDED)

        protected EntityManager em;

cela a bien fonctionné, mais grâce à cela, j'ai constaté qu'ils resteront toujours ouverts, maintenant le printemps ne gérera pas cela. Existe-t-il un moyen de résoudre ce problème en utilisant Spring. Toute aide est grandement appréciée.

Mes entités sont comme -

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

}

Ma configuration Xml est comme -

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

c'est mon dao j'appelle dao via la couche de service

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


}

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

}

c'est le principal

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

Le problème est que lorsque cet appel de méthode retourne:

Category parentCategory=serviceCategory.findCategoryById(2l);

Ici, vous n'êtes plus dans un contexte @Transactional. cela signifie que la session liée à parentCategory a été fermée. Désormais, lorsque vous essayez d'accéder à une collection liée à une session fermée, l'erreur No Session se produit.

Une chose à noter est que la méthode principale s'exécute en dehors de tout bean Spring et n'a aucune notion de contexte de persistance.

La solution consiste à appeler la parentCategory.getAllParentCategoryrefs() à partir d'un contexte transactionnel, qui ne peut jamais être la méthode principale de votre application.

Rattachez ensuite la catégorie parent au nouveau contexte de persistance, puis appelez le getter.

Essayez par exemple de renvoyer la catégorie parent à une méthode transactionnelle du même service:

serviceCategory.nowItWorks(parentCategory);

où la méthode sur le service est transactionnelle:

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

Et dans le DAO:

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

Comme @Zeus l'a dit, cela a déjà été répondu à de nombreuses fois. Vous rencontrez ce problème dans votre classe de test car votre transaction commence et se termine à votre appel de service:

Category parentCategory=serviceCategory.findCategoryById(2l);

Rappelez-vous de la documentation Hibernate que le chargement différé ne fonctionne que dans une session Hibernate (dans ce cas, la session Hibernate commence et se termine avec votre appel de service). Vous ne pouvez pas vous reconnecter à la session de mise en veille prolongée (simplement) pour initialiser la collection.

Je ne sais pas exactement ce que vous voulez dire quand vous voulez le résoudre "au printemps". Puisque ce n'est pas un problème de printemps. Essentiellement, les deux façons de résoudre ce problème consistent à charger la collection dans la session de mise en veille prolongée dans laquelle vous chargez le parent ou à exécuter une extraction distincte en dehors de la session de mise en veille prolongée d'origine.

9
Aaron

utilisez @Fetch(FetchMode.SELECT) et @LazyCollection(LazyCollectionOption.FALSE) sur votre collection d'ensembles de domaines, cela fonctionnera

4
blue shadown