Is the Spring Data Jpa isolation level not working?

41 views Asked by At

Env

  • spring boot 3.1.5
  • mysql 8.031

My thoughts were as follows

  1. a transaction with isolation level set to SERIALZABLE is started.
  2. if the above SERIALZABLE transaction is not finished, but another transaction starts, it will run after the SERIALZABLE transaction finishes.

Isolation Code

@Slf4j
@Service
@RequiredArgsConstructor
public class PersonService {

    private final PersonRepository personRepository; // JpaRepository
    private Long wait = 5000L;

    @Transactional(isolation = Isolation.SERIALIZABLE)
    public List<Person> findAllSERIALIZABLE() throws InterruptedException {
        log.info("SERIALIZABLE ALL start");
        List<Person> all = personRepository.findAll();
        Person person = all.get(0);
        person.setName(String.valueOf(System.currentTimeMillis()));
        Person person1 = all.get(1);
        person1.setName(String.valueOf(System.currentTimeMillis()));
        Thread.sleep(wait);
        log.info("SERIALIZABLE ALL end");
        return personRepository.saveAllAndFlush(all);
    }

    public List<Person> find1And2() {
        log.info("1,2 find start");
        List<Person> allById = personRepository.findAllById(List.of(1L,2L));
        log.info("1,2 find end");
        return allById;
    }
}

Test Code

    @Test
    @DisplayName("SERIALIZABLE find test")
    public void serializableFindTest() throws InterruptedException, ExecutionException {
        CompletableFuture<List<Person>> serializableAll = CompletableFuture.supplyAsync(() -> {
            try {
                return personService.findAllSERIALIZABLE();
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        });

        Thread.sleep(1000);

        CompletableFuture<List<Person>> find1And2 = CompletableFuture.supplyAsync(() -> personService.find1And2());

        List<Person> people = serializableAll.get();
        List<Person> people1 = find1And2.get();

        // then
        Assertions.assertEquals(people1.get(0).getName(),people.get(0).getName());
    }

I thought the order would be

1. serializableAll start, end

2. find1And2 start, end

But the result was different.

2023-11-11T14:23:04.585+09:00  INFO 18864 --- [onPool-worker-1] com.tx.test.service.PersonService        : SERIALIZABLE ALL start
2023-11-11T14:23:04.702+09:00 DEBUG 18864 --- [onPool-worker-1] org.hibernate.SQL                        : 
    select
        p1_0.id,
        p1_0.name 
    from
        person p1_0
Hibernate: 
    select
        p1_0.id,
        p1_0.name 
    from
        person p1_0
2023-11-11T14:23:05.581+09:00  INFO 18864 --- [onPool-worker-2] com.tx.test.service.PersonService        : 1,2 find start
2023-11-11T14:23:05.605+09:00 DEBUG 18864 --- [onPool-worker-2] org.hibernate.SQL                        : 
    select
        p1_0.id,
        p1_0.name 
    from
        person p1_0 
    where
        p1_0.id in (?,?)
Hibernate: 
    select
        p1_0.id,
        p1_0.name 
    from
        person p1_0 
    where
        p1_0.id in (?,?)
2023-11-11T14:23:05.610+09:00  INFO 18864 --- [onPool-worker-2] com.tx.test.service.PersonService        : 1,2 find end
2023-11-11T14:23:09.822+09:00  INFO 18864 --- [onPool-worker-1] com.tx.test.service.PersonService        : SERIALIZABLE ALL end
2023-11-11T14:23:09.887+09:00 DEBUG 18864 --- [onPool-worker-1] org.hibernate.SQL                        : 
    update
        person 
    set
        name=? 
    where
        id=?
Hibernate: 
    update
        person 
    set
        name=? 
    where
        id=?
2023-11-11T14:23:09.891+09:00 DEBUG 18864 --- [onPool-worker-1] org.hibernate.SQL                        : 
    update
        person 
    set
        name=? 
    where
        id=?
Hibernate: 
    update
        person 
    set
        name=? 
    where
        id=?

org.opentest4j.AssertionFailedError: 

I'm not sure if I don't know enough about isolation levels or if I'm setting them up incorrectly.

0

There are 0 answers