2015-01-14 120 views
0

我對Spring的事務管理有點新鮮。我想我錯過了一些配置,但我無法處理它。Spring 4 + Hibernate 4事務管理錯誤

錯誤是我得到failed to lazily initialize a collection of role異常。

我爲我的DAO使用Spring Data。另外,我知道將fetchType設置爲Eager,但這是我想要避免的。

DAO:

public interface CourseDao extends CrudRepository<CourseEntity, Long> { 
    CourseEntity findByName(String name); 
} 

服務:

@Service 
public class CourseMaterialSearchService { 
    private final CourseDao courseDao; 
    private final CourseMaterialEntityTransformer courseMaterialEntityTransformer; 

    @Autowired 
    public CourseMaterialSearchService(CourseDao courseDao, CourseMaterialEntityTransformer courseMaterialEntityTransformer) { 
     super(); 
     this.courseDao = courseDao; 
     this.courseMaterialEntityTransformer = courseMaterialEntityTransformer; 
    } 

    @Transactional 
    public List<CourseMaterial> findMaterialsFor(final Long courseId) { 
     final CourseEntity entity = courseDao.findOne(courseId); 
     final List<CourseMaterialEntity> materials = entity.getCourseMaterialEntityList(); 
     return courseMaterialEntityTransformer.transformEntities(materials); 
    } 
} 

我的應用程序的context.xml是(當然這僅僅是相關部分):

<bean id="entityManagerFactory" 
    class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"> 
    <property name="persistenceUnitName" value="example" /> 
    <property name="dataSource" ref="exampleDataSource" /> 
    <property name="packagesToScan" value="com.example.example.**.repository" /> 
    <property name="jpaVendorAdapter"> 
     <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter"> 
      <property name="showSql" value="true" /> 
      <property name="generateDdl" value="true" /> 
     </bean> 
    </property> 
</bean> 
<tx:annotation-driven proxy-target-class="true" transaction-manager="transactionManager"/> 

<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager"> 
    <property name="entityManagerFactory" ref="entityManagerFactory" /> 
</bean> 

當我在CourseMaterialSearchService中調用findMaterialsFor方法,發生異常。我應該如何解決這個問題?

任何建議,將不勝感激。

謝謝你們。

堆棧跟蹤:

org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: com.example.example.course.repository.domain.CourseEntity.courseMaterialEntityList, could not initialize proxy - no Session 
org.hibernate.collection.internal.AbstractPersistentCollection.throwLazyInitializationException(AbstractPersistentCollection.java:575) 
org.hibernate.collection.internal.AbstractPersistentCollection.withTemporarySessionIfNeeded(AbstractPersistentCollection.java:214) 
org.hibernate.collection.internal.AbstractPersistentCollection.initialize(AbstractPersistentCollection.java:554) 
org.hibernate.collection.internal.AbstractPersistentCollection.read(AbstractPersistentCollection.java:142) 
org.hibernate.collection.internal.PersistentBag.iterator(PersistentBag.java:294) 
com.example.example.course.service.transform.CourseMaterialEntityTransformer.transformEntities(CourseMaterialEntityTransformer.java:15) 
com.example.example.course.service.CourseMaterialSearchService.findMaterialsFor(CourseMaterialSearchService.java:29) 

CourseMaterialEntityTransformer:

public class CourseMaterialEntityTransformer { 
     public List<CourseMaterial> transformEntities(final Iterable<CourseMaterialEntity> entities) { 
      final List<CourseMaterial> result = new ArrayList<>(); 
      for (final CourseMaterialEntity entity : entities) { 
       result.add(transformEntity(entity)); 
      } 
      return result; 
     } 

    public CourseMaterial transformEntity(final CourseMaterialEntity entity) { 
     final CourseMaterial result = new CourseMaterial(); 
     result.setId(entity.getId()); 
     result.setName(entity.getName()); 
     result.setCourseName(entity.getCourseEntity().getName()); 
     result.setCurrentFileName(entity.getCurrentFileName()); 
     result.setOriginalFileName(entity.getOriginalFileName()); 
     result.setCategory(entity.getMaterialCategoryEntity().getName()); 
     result.setUploader(entity.getUserEntity().getName()); 
     return result; 
    } 
} 

com.example.example.course.service.transform.CourseMaterialEntityTransformer.transformEntities(CourseMaterialEntityTransformer.java:15)

for (final CourseMaterialEntity entity : entities) { 

CourseEntity:

@Entity(name = "courses") 
public class CourseEntity { 
    @Id 
    @GeneratedValue 
    private Long id; 

    private String name; 

    @OneToMany(mappedBy = "courseEntity") 
    private List<CourseMaterialEntity> courseMaterialEntityList; 

    public Long getId() { 
     return id; 
    } 

    public void setId(final Long id) { 
     this.id = id; 
    } 

    public String getName() { 
     return name; 
    } 

    public void setName(final String name) { 
     this.name = name; 
    } 

    public List<CourseMaterialEntity> getCourseMaterialEntityList() { 
     return courseMaterialEntityList; 
    } 

    public void setCourseMaterialEntityList(final List<CourseMaterialEntity> courseMaterialEntityList) { 
     this.courseMaterialEntityList = courseMaterialEntityList; 
    } 

} 
+0

post stacktrace log –

+0

我的問題已更新。 – galovics

+0

plz發佈域對象以及 –

回答

1

Spring使用AOP應用事務。 bean上的AOP僅適用於相同應用程序上下文中的bean。

您在application-context.xml中有<tx:annotation-driven />,這是由ContextLoaderListener加載的。該文件包含一個<context:component-scan />,它檢測到@Service

但是,如果您在由DispatcherServlet加載的文件中也具有相同的<context:component-scan />,或者至少檢測到相同的@Service,則會導致此服務的另一個實例不會應用AOP。

作爲一般規則的拇指要加載的一切,但在你的DispatcherServlet@ControllersContextLoaderListener和唯一的網絡有關的東西(視圖解析器,@Controllers)。

請參閱context depended scan-component filter

0

您正嘗試訪問事務外部的延遲加載屬性。該對象然後與EntityManager(數據庫)沒有連接,因爲它不在事務中,因此無法獲取延遲加載的屬性。

+0

埃姆,好吧,但如何解決它?如果我在findMaterialsFor方法中調用entity.getCourseMaterialEntityList()。size(),它應該工作正確嗎? – galovics

+0

他在方法之上有'@ Transactional',所以它應該在'@ Transactional'範圍內。 – Mior

+0

僅當事務管理器正確設置才能處理註釋。錯誤信息就是這樣,這就是我在答案中提供的解釋。 – Tobb

0

默認情況下集合是延遲加載的。您可以在下面的代碼替換:

@OneToMany(mappedBy = "courseEntity") 
private List<CourseMaterialEntity> courseMaterialEntityList; 

有了:

@OneToMany(fetch = FetchType.EAGER, mappedBy = "courseEntity", cascade = CascadeType.ALL) 
private List<CourseMaterialEntity> courseMaterialEntityList; 
+0

我不想急切地拿它,這就是我想要避免的。 – galovics

0

您需要更改@OneToMany(mappedBy = "courseEntity")@OneToMany(mappedBy = "courseEntity", fetch = FetchType.EAGER, cascade = CascadeType.ALL)

默認提取類型是懶惰的,所以當你試圖訪問集合它尚未從數據庫加載。

+0

我不想急切地拿。 – galovics

+0

這不一定要熱切。問題出在交易中,他試圖以不知何故的方式加載實體。 – Mior

+0

'CourseMaterialEntity'看起來像什麼? –