我有一个关于我的Spring MVC 3和JPA / Hibernate设置的两部分问题。
首先,我是否在我的服务方法上添加@Transactional注释并不重要,它总是有效,我发现它很奇怪。当我忘记添加@Transactional注释时,我习惯于抱怨他们没有交易的方法。
这是我在application-context.xml文件中设置的事务。
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean" p:dataSource-ref="dataSource"/>
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager" p:entityManagerFactory-ref="entityManagerFactory"/>
<tx:annotation-driven transaction-manager="transactionManager"/>
其次,当我使用服务方法获取Category时,我得到一个Category对象。据我所知,它不是代理,而是一个真实的对象,设置了大多数属性。当我使用该类别搜索课程时,它出错了:
public List<Course> findCourses(Category category) {
Query queryGood = entityManager.createQuery("select c from Course c join fetch c.company where c.category.id = :categoryId");
Query queryBad = entityManager.createQuery("from Course c where c.category = :category");
queryGood.setParameter("categoryId", category.getId());
queryBad.setParameter("category", category);
List<Category> categoriesGood = queryGood.getResultList(); // THIS WORKS!
List<Category> categoriesBad = queryBad.getResultList(); // THIS THROWS AN EXCEPTION
return null;
}
queryBad的执行会导致以下异常:
org.springframework.dao.InvalidDataAccessApiUsageException:
org.hibernate.TransientObjectException: object references an unsaved
transient instance - save the transient instance before flushing:
nl.myapp.domain.Category; nested exception is java.lang.IllegalStateException:
org.hibernate.TransientObjectException: object references an unsaved transient instance
- save the transient instance before flushing: nl.myapp.domain.Category
org.springframework.orm.jpa.EntityManagerFactoryUtils.convertJpaAccessExceptionIfPossible(EntityManagerFactoryUtils.java:298)
你知道为什么(1)我的应用程序在不使用@Transactional注释的情况下获取数据,以及2)为什么Hibernate会抛出这个TransientObjectException?
答案 0 :(得分:1)
别介意。 Hibernate正在以应有的方式做出反应。我使用了一个@Transactional服务方法来获取Category并使用该Category作为另一个@Transactional服务方法的输入。当你这样做时,Hibernate为新的第二个服务方法调用创建一个新会话(因为它有自己的Transactional注释),并且在新会话中找不到Category。这就是抛出TransientObject异常的原因。我现在只是使用Category的id作为seciond服务方法调用的参数,这是有效的。