[리팩토링]동시성 문제 - 읽기 3가지

  1. 더티 리드 (Dirty Read)
    • 트랙잭션 A 가 아직 커밋되지 않은 변경을 만든 경우,
    • 트랜잭션 B 가 해당 변경을 읽는 현상
    @Transactional(isolation = Isolation.READ_UNCOMMITTED)
    public void dirtyReadSimulation() {
        User user = userRepository.findById(1L).orElseThrow();
        user.setBalance(user.getBalance() - 100);
        // 이 지점에서 다른 트랜잭션에서 사용자의 잔액을 읽을 수 있으며 더티 리드가 발생할 수 있습니다.
    }
  1. 반복 불가능 리드 (Non-repeatable Read)
    • 트랜잭션 A가 같은 레코드를 두 번 읽고
    • 그 사이에 트랜잭션 B 가 해당 레코드를 변경하고 커밋하는 현상
    @Transactional(isolation = Isolation.READ_COMMITTED)
    public void nonRepeatableReadSimulation() {
        User user = userRepository.findById(1L).orElseThrow();
        System.out.println("Initial Balance: " + user.getBalance());
    
        // 이 지점에서 다른 트랜잭션에서 사용자의 잔액을 변경하고 커밋할 수 있습니다.
    
        User userAgain = userRepository.findById(1L).orElseThrow();
        System.out.println("Balance after other transaction commits: " + userAgain.getBalance());
    }
  1. 팬텀 리드 (Phantom Read)
    • 트랜잭션 A가 특정 범위를 레코드를 읽고
    • 그 사이에, 트랜잭션 B가 그 범위에 새로운 레코드를 추가하거나 제거하고 커밋하는 현상
    @Transactional(isolation = Isolation.REPEATABLE_READ)
    public void phantomReadSimulation() {
        List<User> users = userRepository.findByBalanceGreaterThan(1000);
        System.out.println("Number of users with balance > 1000: " + users.size());
    
        // 이 지점에서 다른 트랜잭션에서 잔액이 1000보다 큰 새 사용자를 추가하고 커밋할 수 있습니다.
    
        List<User> usersAgain = userRepository.findByBalanceGreaterThan(1000);
        System.out.println("Number of users with balance > 1000 after other transaction commits: " + usersAgain.size());
    }


Uploaded by N2T