多线程JPA测试不会回滚,为什么?为什么?

nhn9ugyo  于 2023-10-19  发布在  其他
关注(0)|答案(1)|浏览(127)

下面是simple @DataJPATest的一部分。两个测试是相同的。
当它在单个线程中执行时,回滚没有问题。

@Test
    void SingleThreadTest1() throws RequesterException, InterruptedException {
        System.out.println("(before)count: " + logRepository.count());
        App app = appRepository.findByName("TestApp").orElseThrow();
        myService.loggingTransaction(app);
        System.out.println("(after)count: " + logRepository.count());
    }

    @Test
    void SingleThreadTest2() throws RequesterException, InterruptedException {
        System.out.println("(before)count: " + logRepository.count());
        App app = appRepository.findByName("TestApp").orElseThrow();
        myService.loggingTransaction(app);
        System.out.println("(after)count: " + logRepository.count());
    }

测试结果:

#SingleThreadTest1
    (before)count: 0
    (after)count: 1

    #SingleThreadTest2
    (before)count: 0
    (after)count: 1

但在多线程中操作时不会回滚。

@DataJpaTest
class ServiceTest {
    static final int CONCURRENCY = 1;

    @Test
    void MultiThreadTest1() throws RequesterException, InterruptedException {
        System.out.println("(before)count: " + logRepository.count());
        App app = appRepository.findByName("TestApp").orElseThrow();
        // --------From Here: Spawn sub thread---------
        ThreadPoolExecutor executor = new ThreadPoolExecutor(CONCURRENCY, CONCURRENCY, 1, TimeUnit.MINUTES, new SynchronousQueue<>());
        executor.prestartAllCoreThreads();
        List<Callable<OptoutMessage>> callables = IntStream.range(0, CONCURRENCY)
                .<Callable<OptoutMessage>>mapToObj(i -> () -> myService.loggingTransaction(app))
                .toList();
        List<Future<OptoutMessage>> futures = executor.invokeAll(callables);
        executor.shutdownNow();
        // ------------------Ultil here----------------
        System.out.println("(after)count: " + logRepository.count());
    }
    
    @Test
    void MultiThreadTest2() throws RequesterException, InterruptedException {
        System.out.println("(before)count: " + logRepository.count());
        App app = appRepository.findByName("TestApp").orElseThrow();
        // --------From Here: Spawn sub thread---------
        ThreadPoolExecutor executor = new ThreadPoolExecutor(CONCURRENCY, CONCURRENCY, 1, TimeUnit.MINUTES, new SynchronousQueue<>());
        executor.prestartAllCoreThreads();
        List<Callable<OptoutMessage>> callables = IntStream.range(0, CONCURRENCY)
                .<Callable<OptoutMessage>>mapToObj(i -> () -> myService.loggingTransaction(app))
                .toList();
        List<Future<OptoutMessage>> futures = executor.invokeAll(callables);
        executor.shutdownNow();
        // ------------------Ultil here----------------
        System.out.println("(after)count: " + logRepository.count());
    }

测试结果:

#MultiThreadTest1
    (before)count: 0
    (after)count: 1

    #MultiThreadTest2
    (before)count: 1 // <- IT SHOULD BE 0 !!!
    (after)count: 2

问题:

1.为什么@DataJPATest在子线程中发生事务时不回滚?
1.在这种情况下,我应该如何回滚@Test之后的数据?

kokeuurv

kokeuurv1#

我们最近遇到了类似的问题。
问题1:我不能给予一个充分的答案,因为我也不知道它为什么不回滚。
问题2:对我们有效的是添加注解

@DirtiesContext

https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/test/annotation/DirtiesContext.html

相关问题