Env
- spring boot 3.1.5
- mysql 8.031
My thoughts were as follows
- a transaction with isolation level set to SERIALZABLE is started.
- 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.