Spring测试事务线程

Spring测试事务线程,spring,transactions,spring-data-jpa,integration-testing,Spring,Transactions,Spring Data Jpa,Integration Testing,我已经将同步进程移到了异步进程,现在我在维护集成测试方面遇到了一些麻烦。这似乎与以下事实有关:当您在@Transactional方法内创建一个新线程,然后调用一个新的@Transactional时,Spring将创建一个新事务 在集成测试期间,@Transactional tests会出现问题。由于测试配置中的TransactionalTestExecutionListener,线程事务似乎在测试完成之前回滚 我试过很多东西,比如 -自动连接EntityManager并在线程完成后手动刷新 -在

我已经将同步进程移到了异步进程,现在我在维护集成测试方面遇到了一些麻烦。这似乎与以下事实有关:当您在@Transactional方法内创建一个新线程,然后调用一个新的@Transactional时,Spring将创建一个新事务

在集成测试期间,@Transactional tests会出现问题。由于测试配置中的TransactionalTestExecutionListener,线程事务似乎在测试完成之前回滚

我试过很多东西,比如 -自动连接EntityManager并在线程完成后手动刷新 -在测试方法中使用@Rollback而不是@Transactional -使用TestTransaction管理事务 -同时使用@Rollback和TestTransaction

以下是简化的源代码:

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集合
私人名单