为啥 JPA 提交在应用程序中失败,但在 JUnit 中有效?
Posted
技术标签:
【中文标题】为啥 JPA 提交在应用程序中失败,但在 JUnit 中有效?【英文标题】:Why JPA commit fails in Application, but works in JUnit?为什么 JPA 提交在应用程序中失败,但在 JUnit 中有效? 【发布时间】:2014-11-26 19:26:50 【问题描述】:我正在尝试在 JUnit 中重现我在 Spring Boot 应用程序中的 JPA 异常。
申请(提交失败):
@Import(RepositoryRestMvcConfiguration.class)
@EnableAutoConfiguration
@ActiveProfiles("dev")
public class Application implements CommandLineRunner
public static void main(final String[] args)
SpringApplication.run(Application.class, args);
@Inject
Repository1 repository1;
...
@Inject
RepositoryN repositoryN;
@Override
public void run(final String... args) throws Exception
// Populating database with demo data
repository1.save(entity1);
...
// fails on save entityN
repositoryN.save(entityN);
JUnit(有效 - 为什么?):
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = PersistenceConfig.class, DataConfig.class ,
loader = AnnotationConfigContextLoader.class)
@Transactional("transactionManager.data")
@ActiveProfiles("dev")
public class BuildingFloorsRoomsRepositoryTest
@Inject
Repository1 repository1;
...
@Inject
RepositoryN repositoryN;
@Test
@Rollback(false)
public void saveEntities()
repository1.save(entity1);
...
repositoryN.save(entityN);
// works - why?
例外:
Caused by: org.hibernate.PersistentObjectException: detached entity passed to persist: com.archibus.domain.hierarchy.Node
at org.hibernate.event.internal.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:139)
at org.hibernate.internal.SessionImpl.firePersist(SessionImpl.java:801)
at org.hibernate.internal.SessionImpl.persist(SessionImpl.java:794)
at org.hibernate.jpa.event.internal.core.JpaPersistEventListener$1.cascade(JpaPersistEventListener.java:97)
at org.hibernate.engine.internal.Cascade.cascadeToOne(Cascade.java:350)
at org.hibernate.engine.internal.Cascade.cascadeAssociation(Cascade.java:293)
at org.hibernate.engine.internal.Cascade.cascadeProperty(Cascade.java:161)
at org.hibernate.engine.internal.Cascade.cascade(Cascade.java:118)
at org.hibernate.event.internal.AbstractSaveEventListener.cascadeBeforeSave(AbstractSaveEventListener.java:432)
at org.hibernate.event.internal.AbstractSaveEventListener.performSaveOrReplicate(AbstractSaveEventListener.java:265)
at org.hibernate.event.internal.AbstractSaveEventListener.performSave(AbstractSaveEventListener.java:194)
at org.hibernate.event.internal.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:125)
at org.hibernate.jpa.event.internal.core.JpaPersistEventListener.saveWithGeneratedId(JpaPersistEventListener.java:84)
at org.hibernate.event.internal.DefaultPersistEventListener.entityIsTransient(DefaultPersistEventListener.java:206)
at org.hibernate.event.internal.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:149)
at org.hibernate.internal.SessionImpl.firePersist(SessionImpl.java:801)
at org.hibernate.internal.SessionImpl.persist(SessionImpl.java:794)
at org.hibernate.jpa.event.internal.core.JpaPersistEventListener$1.cascade(JpaPersistEventListener.java:97)
at org.hibernate.engine.internal.Cascade.cascadeToOne(Cascade.java:350)
at org.hibernate.engine.internal.Cascade.cascadeAssociation(Cascade.java:293)
at org.hibernate.engine.internal.Cascade.cascadeProperty(Cascade.java:161)
at org.hibernate.engine.internal.Cascade.cascade(Cascade.java:118)
at org.hibernate.event.internal.AbstractSaveEventListener.cascadeBeforeSave(AbstractSaveEventListener.java:432)
at org.hibernate.event.internal.AbstractSaveEventListener.performSaveOrReplicate(AbstractSaveEventListener.java:265)
at org.hibernate.event.internal.AbstractSaveEventListener.performSave(AbstractSaveEventListener.java:194)
at org.hibernate.event.internal.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:125)
at org.hibernate.jpa.event.internal.core.JpaPersistEventListener.saveWithGeneratedId(JpaPersistEventListener.java:84)
at org.hibernate.event.internal.DefaultPersistEventListener.entityIsTransient(DefaultPersistEventListener.java:206)
at org.hibernate.event.internal.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:149)
at org.hibernate.event.internal.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:75)
at org.hibernate.internal.SessionImpl.firePersist(SessionImpl.java:811)
at org.hibernate.internal.SessionImpl.persist(SessionImpl.java:784)
at org.hibernate.internal.SessionImpl.persist(SessionImpl.java:789)
at org.springframework.data.jpa.repository.support.SimpleJpaRepository.save(SimpleJpaRepository.java:389)
【问题讨论】:
【参考方案1】:我可以看到的区别是测试是在事务中运行的。尝试在@Transactional
或类似的事务中执行run
。
【讨论】:
以上是关于为啥 JPA 提交在应用程序中失败,但在 JUnit 中有效?的主要内容,如果未能解决你的问题,请参考以下文章
合并有时在 JPA Hibernate 中失败,但在同一事务中 PERSIST 有效
无法提交 JPA 事务:事务标记为 rollbackOnly
简单的多行正则表达式在 .NET 中失败,但在 ECMAScript 中成功 - 为啥?