Spring测试事务线程
我已经将同步进程移到了异步进程,现在我在维护集成测试方面遇到了一些麻烦。这似乎与以下事实有关:当您在@Transactional方法内创建一个新线程,然后调用一个新的@Transactional时,Spring将创建一个新事务 在集成测试期间,@Transactional tests会出现问题。由于测试配置中的TransactionalTestExecutionListener,线程事务似乎在测试完成之前回滚 我试过很多东西,比如 -自动连接EntityManager并在线程完成后手动刷新 -在测试方法中使用@Rollback而不是@Transactional -使用TestTransaction管理事务 -同时使用@Rollback和TestTransaction 以下是简化的源代码:Spring测试事务线程,spring,transactions,spring-data-jpa,integration-testing,Spring,Transactions,Spring Data Jpa,Integration Testing,我已经将同步进程移到了异步进程,现在我在维护集成测试方面遇到了一些麻烦。这似乎与以下事实有关:当您在@Transactional方法内创建一个新线程,然后调用一个新的@Transactional时,Spring将创建一个新事务 在集成测试期间,@Transactional tests会出现问题。由于测试配置中的TransactionalTestExecutionListener,线程事务似乎在测试完成之前回滚 我试过很多东西,比如 -自动连接EntityManager并在线程完成后手动刷新 -在
public interface MyService{
public void doThing(someArgs...);
public void updateThings(someArgs...);
}
@Service
public class MyServiceImpl implements MyService{
@Autowired
private AsynchronousFutureHandlerService futureService;
@Autowired
@Qualifier("myExecutorService")
private ScheduledExecutorService myExecutorService;
@Transactional
@Override
public void doThing(someArgs...){
doThingAsync(someArgs...);
}
private void doThingAsync(someArgs...){
AsynchronousHandler runnable = applicationContext.getBean(
AsynchronousHandler.class, someArgs...);
//as we are executing some treatment in a new Thread, a new transaction is automatically created
Future<?> future = myExecutorService.submit(runnable);
//keep track of thread execution
futureService.addFutures(future);
}
@Override
@Transactional
public void updateThings(someArgs...){
//do udpate stuff
}
}
/**
* very basic solution to improve later to consult thread state
*/
@Service
public class AsynchronousFutureHandlerService {
//TODO : pass to ThreadSafe collection
private List<Future<?>> futures = new ArrayList<>();
public void addTheoreticalApplicationFuture(Future<?> future){
futures.add(future);
this.deleteJobsDone();
}
public boolean isThreadStillRunning(){
boolean stillRunning = false;
for(Future<?> f : futures){
if(!f.isDone()){
stillRunning = true;
break;
}
}
return stillRunning;
}
public void deleteJobsDone(){
this.futures.removeIf(f -> f.isDone());
}
}
@Component
@Scope("prototype")
public class AsynchronousHandler implements Runnable {
@Autowired
private MyService myService;
@Override
public void run() {
myService.updateThings(...); //updates data in DB
...
}
}
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = TestConfiguration.class)
@TestExecutionListeners({ DependencyInjectionTestExecutionListener.class, DataSetTestExecutionListener.class,
TransactionalTestExecutionListener.class })
@DataSet(dbType = DBType.H2, locations = { "classpath:dataset.xml" })
public class MyServiceTest{
@Autowired
private MyService myService;
@Autowired
private AsynchronousFutureHandlerService futureService;
@Test
@Transactional
public void test_doThings(){
myService.doThings(someArgs...);
waitUpdateFinish();
Assert.assertEquals(...); //fails here because Thread transaction has been rollbacked
}
private void waitUpdateFinish() throws InterruptedException{
while(futureService.isThreadStillRunning()){
Thread.sleep(500);
}
}
}
公共接口MyService{
公共空间点滴(某些参数…);
公共无效更新(某些参数…);
}
@服务
公共类MyServiceImpl实现了MyService{
@自动连线
专用异步FutureHandlerService futureService;
@自动连线
@限定符(“myExecutorService”)
专用ScheduledExecutorService myExecutorService;
@交易的
@凌驾
公共空点(某些参数…){
doThingAsync(某些参数…);
}
私有void doThingAsync(某些参数…){
AsynchronousHandler runnable=applicationContext.getBean(
AsynchronousHandler.class,someArgs;
//当我们在一个新线程中执行某些处理时,会自动创建一个新事务
Future=myExecutorService.submit(可运行);
//跟踪线程执行情况
futureService.addFutures(未来);
}
@凌驾
@交易的
公共无效更新(某些参数…){
//你做什么
}
}
/**
*非常基本的解决方案,以后要改进,请参考线程状态
*/
@服务
公共类异步FutureHandlerService{
//TODO:传递到ThreadSafe集合
私人名单