Java Spring在单元测试中运行线程时找不到实体

Java Spring在单元测试中运行线程时找不到实体,java,spring,jpa,testing,Java,Spring,Jpa,Testing,我有一个Spring应用程序的单元测试,基本上如下所示: @Test @Transactional public void myTest() { long id = createAndFlushMyEntity(); doSomething(); } @Test @Transactional public void myTest() { long id = createAndFlushMyEntity(); assertEntityIsPrese

我有一个Spring应用程序的单元测试,基本上如下所示:

@Test
@Transactional
public void myTest() {
    long id = createAndFlushMyEntity();
    doSomething();
}
@Test
@Transactional
public void myTest() {        
    long id = createAndFlushMyEntity();
    assertEntityIsPresent(id); // works
    new Thread() {
        public void run() {
            assertEntityIsPresent(id); // doesn't work!
            doSomething();
        }
    }.start();   
}
此测试(以及应用程序本身)运行良好。但是,当我将代码放入线程时,它就不再工作了:

@Test
@Transactional
public void myTest() {
    long id = createAndFlushMyEntity();
    new Thread() {
        public void run() {
            doSomething();
        }
    }.start();   
}
我得到以下例外情况:

javax.persistence.EntityNotFoundException: Unable to find BankConnection with id 1003
    at org.hibernate.ejb.Ejb3Configuration$Ejb3EntityNotFoundDelegate.handleEntityNotFound(Ejb3Configuration.java:157)
    at org.hibernate.event.internal.DefaultLoadEventListener.load(DefaultLoadEventListener.java:212)
    at org.hibernate.event.internal.DefaultLoadEventListener.proxyOrLoad(DefaultLoadEventListener.java:262)
    at org.hibernate.event.internal.DefaultLoadEventListener.onLoad(DefaultLoadEventListener.java:150)
    at org.hibernate.internal.SessionImpl.fireLoad(SessionImpl.java:1092)
    at org.hibernate.internal.SessionImpl.internalLoad(SessionImpl.java:1019)
    at org.hibernate.type.EntityType.resolveIdentifier(EntityType.java:672)
    at org.hibernate.type.EntityType.resolve(EntityType.java:490)
    at org.hibernate.type.EntityType.replace(EntityType.java:354)
    at org.hibernate.type.AbstractType.replace(AbstractType.java:178)
    at org.hibernate.type.TypeHelper.replace(TypeHelper.java:211)
    at org.hibernate.event.internal.DefaultMergeEventListener.copyValues(DefaultMergeEventListener.java:409)
    at org.hibernate.event.internal.DefaultMergeEventListener.entityIsTransient(DefaultMergeEventListener.java:214)
    at org.hibernate.event.internal.DefaultMergeEventListener.entityIsDetached(DefaultMergeEventListener.java:282)
    at org.hibernate.event.internal.DefaultMergeEventListener.onMerge(DefaultMergeEventListener.java:151)
    at org.hibernate.event.internal.DefaultMergeEventListener.onMerge(DefaultMergeEventListener.java:76)
    at org.hibernate.internal.SessionImpl.fireMerge(SessionImpl.java:914)
    at org.hibernate.internal.SessionImpl.merge(SessionImpl.java:898)
    at org.hibernate.internal.SessionImpl.merge(SessionImpl.java:902)
    at org.hibernate.ejb.AbstractEntityManagerImpl.merge(AbstractEntityManagerImpl.java:889)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:606)
    at org.springframework.orm.jpa.SharedEntityManagerCreator$SharedEntityManagerInvocationHandler.invoke(SharedEntityManagerCreator.java:241)
    at com.sun.proxy.$Proxy66.merge(Unknown Source)
    at org.springframework.data.jpa.repository.support.SimpleJpaRepository.save(SimpleJpaRepository.java:361)
    at org.springframework.data.jpa.repository.support.SimpleJpaRepository.saveAndFlush(SimpleJpaRepository.java:372)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:606)
    at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.executeMethodOn(RepositoryFactorySupport.java:344)
    at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.invoke(RepositoryFactorySupport.java:329)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
    at org.springframework.transaction.interceptor.TransactionInterceptor$1.proceedWithInvocation(TransactionInterceptor.java:96)
    at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:260)
    at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:94)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
    at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:155)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
    at org.springframework.data.jpa.repository.support.LockModeRepositoryPostProcessor$LockModePopulatingMethodIntercceptor.invoke(LockModeRepositoryPostProcessor.java:92)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
    at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:91)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
    at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:204)
    at com.sun.proxy.$Proxy120.saveAndFlush(Unknown Source)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:606)
    at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:317)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:183)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:150)
    at org.springframework.transaction.interceptor.TransactionInterceptor$1.proceedWithInvocation(TransactionInterceptor.java:96)
    at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:260)
    at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:94)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
    at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:204)
    at com.sun.proxy.$Proxy121.updateState(Unknown Source)
    at java.util.concurrent.FutureTask.run(FutureTask.java:262)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
    at java.lang.Thread.run(Thread.java:745)
因此,在我的线程中,Spring/JPA找不到我之前创建的实体。如果我移除线程,一切正常,实体就在那里。我也可以这样做:

@Test
@Transactional
public void myTest() {
    long id = createAndFlushMyEntity();
    doSomething();
}
@Test
@Transactional
public void myTest() {        
    long id = createAndFlushMyEntity();
    assertEntityIsPresent(id); // works
    new Thread() {
        public void run() {
            assertEntityIsPresent(id); // doesn't work!
            doSomething();
        }
    }.start();   
}
测试本身有一个
@Transactional
注释。在调用线程之前,我还刷新了我的JPA存储库。因此,实体肯定应该在那里(在我看来)。但事实并非如此

有什么想法吗

我的目标是用多线程测试
doSomething
方法。也许有更优雅的方法,比如手工创建线程

编辑:
doSomething
仅为实体设置属性:

doSomething() {
    Entity entity = repository.findOne(1L); // entity is NULL!
    entity.setState("state");
    repository.saveAndFlush(entity);
}

因为它不在那里。。。没有提交,因此当前正在运行的事务之外的任何内容都无法查看数据。线程在事务的作用域之外(事务是线程绑定的)。那么我如何进行提交呢?我想
saveAndFlush
可以吗?没有flush!=提交它只发出查询,不提交任何内容。此外,如果您提交,您的数据将永久保存在数据库中,但不确定这是否是您想要的。您想测试什么?我使用H2数据库进行测试,所以提交事务是可以的。我想测试以下内容:只允许为实体设置某些状态,例如,如果状态为“取消”,则不允许将状态设置为“成功”。我想为此编写一个集成测试(不仅调用实体的setter),因为我想测试整个过程。然后在测试之前(而不是在测试内部)设置数据,imho不应该依赖于数据库中的状态,而是实际对象的状态。。。因此,不确定您为什么想要一个线程来测试它(或者您认为除了测试用例的复杂性之外,您还可以通过该线程获得什么)。