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
}
}
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());
}
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.
utilisez @Fetch(FetchMode.SELECT)
et @LazyCollection(LazyCollectionOption.FALSE)
sur votre collection d'ensembles de domaines, cela fonctionnera