Home ISOLATION LEVEL의 관습적 사용
Post
Cancel

ISOLATION LEVEL의 관습적 사용

글을 작성하게 된 계기


ISOLATION LEVEL을 관습적으로 사용하던 것을 느꼈고, 이를 정리하기 위해 글을 작성하게 되었습니다.





1. 왜 이런 고민을 하게 됐을까?


문제가 발생했던 것은 아닌데요, 스프링에서 @Transactional을 사용할 때, 관습적으로 REPEATABLE READ 만 사용하고 있는 것을 느꼈습니다. 별도 설정을 하지 않으면 MySQL은 기본적으로 REPEATABLE READ를 사용하기 때문입니다.

1
2
3
4
5
6
mysql> SHOW VARIABLES LIKE 'transaction_isolation';
+-----------------------+-----------------+
| Variable_name         | Value           |
+-----------------------+-----------------+
| transaction_isolation | REPEATABLE-READ |
+-----------------------+-----------------+

InnoDB offers all four transaction isolation levels described by the SQL:1992 standard: READ UNCOMMITTED, READ COMMITTED, REPEATABLE READ, and SERIALIZABLE. The default isolation level for InnoDB is REPEATABLE READ.





격리 수준을 별도로 지정하지 않을 경우, 데이터베이스의 기본 격리 수준 을 따르는 것을 볼 수 있습니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
public abstract class DataSourceUtils {

    ......
    
    @Nullable
    public static Integer prepareConnectionForTransaction(Connection con, @Nullable TransactionDefinition definition) {
        
        ......

        // Apply specific isolation level, if any.
        Integer previousIsolationLevel = null;
        if (definition != null && definition.getIsolationLevel() != TransactionDefinition.ISOLATION_DEFAULT) {
            if (debugEnabled) {
                logger.debug("Changing isolation level of JDBC Connection [" + con + "] to " +
                    definition.getIsolationLevel());
            }
            int currentIsolation = con.getTransactionIsolation();
            if (currentIsolation != definition.getIsolationLevel()) {
                previousIsolationLevel = currentIsolation;
                con.setTransactionIsolation(definition.getIsolationLevel());
            }
        }

        return previousIsolationLevel;
    }
}





이 과정에서 MySQL의 기본 격리 수준인 REPEATABLE READ 가 항상 최선일까 하는 의문이 들었습니다. 쓰기 작업 중 다른 트랜잭션이 값을 변경 하거나 팬텀 리드 가 발생할 일이 적다면 굳이 REPEATABLE READ를 사용할 필요가 없으니까요.

REPEATABLE READ - InnoDB locks the index range scanned, using gap locks or next-key locks to block insertions by other sessions into the gaps covered by the range.







2. 어떻게 사용하는 것이 좋을까?


따라서 쓰기 작업에서 다른 트랜잭션이 값을 변경할 가능성이 없으며, 팬텀리드가 발생할 가능성이 적다면 READ COMMITTED 를 사용하기로 했습니다. 예를 들어, 사용자 정보 조회 같이요. 개인 정보는 본인만 변경하기 때문에 다른 쓰기 작업에서 값이 변경되거나 팬텀 리드도 거의 발생하지 않기 때문입니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
@Service
public class UserService {
    
    ......

    @Transactional(isolation = Isolation.READ_COMMITTED)
    public User findById(final Long userId) {
        return userRepository.findById(userId);
    }

    @Transactional(isolation = Isolation.READ_COMMITTED)
    public void updateUser(
        final Long userId,
        final UserInfoUpdateCommand command
    ) {
        final User user = userRepository.findById(userId)
            .orElseThrow(() -> new UserNotFoundException(userId));
        
        ......
    }
}







3. 정리


기본적으로는 REPEATABLE_READ 를 사용하는 것이 좋습니다. 굳이 위험 리스크를 감수할 필요는 없으니까요. 다만 최근 대량 데이터를 다루면서 이런 사소한 포인트 하나가 전체 성능에 꽤 큰 영향을 미칠 수 있다는 것을 깨닫고 난 후, 세부 설정을 꼼꼼히 보는 습관이 생겼는데, 이런 경우도 있다 정도만 알고 있으면 좋을 것 같네요. 👀


This post is licensed under CC BY 4.0 by the author.

외부 API 문서화

LOAD DATA의 중복 데이터 삽입 방지