✅ 개요

Spring에서는 @Transactional을 통해 트랜잭션을 선언적으로 처리할 수 있고, 그 안의 isolation 옵션은 트랜잭션 간 동시성 제어의 수준을 지정해주는 설정입니다.

그중에서도 Isolation.SERIALIZABLE은 가장 높은 수준의 격리 수준으로, 모든 트랜잭션이 마치 하나씩 순서대로 실행되는 것처럼 보장해줍니다.

📌 트랜잭션 격리 수준(Isolation Level)이란?

여러 트랜잭션이 동시에 실행될 때, 서로 간의 읽기/쓰기 충돌을 얼마나 허용할지를 결정하는 규칙입니다.

트랜잭션 간 발생할 수 있는 3가지 주요 문제

문제 이름 설명 막는 격리 수준
Dirty Read 아직 커밋되지 않은 값을 다른 트랜잭션이 읽음 READ COMMITTED 이상
Non-Repeatable Read 같은 쿼리를 두 번 했는데 결과가 달라짐 REPEATABLE READ 이상
Phantom Read 조건은 같은데 행 개수가 달라짐 (새 row 등장) SERIALIZABLE만 방지

✅ Isolation.SERIALIZABLE의 의미

@Transactional(isolation = Isolation.SERIALIZABLE)
public void doSomething() {
    // 이 안의 모든 DB 접근은 완전히 직렬화된 것처럼 동작함
}

🧪 예제 코드 (팬텀 리드 방지)

💥 문제 코드 (REPEATABLE READ)

@Transactional(isolation = Isolation.REPEATABLE_READ)
public void insertUserIfNotExists(String name) {
    if (userRepository.findByName(name).isEmpty()) {
        // 동시에 들어오면 두 트랜잭션 모두 여기 통과함
        userRepository.save(new User(name));
    }
}

✅ 해결 코드 (SERIALIZABLE)

@Transactional(isolation = Isolation.SERIALIZABLE)
public void insertUserIfNotExists(String name) {
    if (userRepository.findByName(name).isEmpty()) {
        userRepository.save(new User(name));
    }
}