728x90

이번 글에서는 트랜잭션의 격리수준에 대해서 집중적으로 작성했습니다.
스프링(Spring)에서는 트랜잭션의 격리 수준(Isolation Level) 을 설정하여 다른 트랜잭션과 얼마나 독립적으로 실행될지를 결정할 수 있습니다. 올바른 격리 수준을 선택하면 성능과 데이터 일관성 사이에서 균형을 맞출 수 있습니다.

스프링에서 트랜잭션의 격리 수준을 설정할 때는 @Transactional(isolation = Isolation.XXX)을 사용합니다.


1. READ UNCOMMITTED (가장 낮은 격리 수준)

아직 커밋되지 않은 데이터도 읽을 수 있는 상태

문제점: Dirty Read(더티 리드) 발생 가능

사용 예시: 데이터 일관성이 덜 중요하고 성능이 중요한 경우

@Transactional(isolation = Isolation.READ_UNCOMMITTED)
public void readUncommittedExample() {
    accountRepository.findBalanceById(1);
}

예제(Dirty Read 발생 가능)

  1. 트랜잭션 A가 계좌 잔액을 1000원 → 500원으로 변경했지만 아직 COMMIT 하지 않음
  2. 트랜잭션 B가 계좌를 조회하면 500원이 보임 (실제로는 커밋이 안 됐는데도)
  3. 이후 트랜잭션 A가 ROLLBACK 하면 원래 1000원으로 돌아가는데, B는 500원을 잘못 읽었음

Read Uncommitted는 일반적으로 잘 사용되지 않는 설정이다. 정확성이 불필요한 조회만 한다거나, 정말 성능이 중요한게 아니라면 고려하지 말자.


2. READ COMMITTED (기본적인 격리 수준)

커밋된 데이터만 읽을 수 있도록 보장

문제점: Non-Repeatable Read(반복 불가능한 읽기) 발생 가능

사용 예시: 일반적인 애플리케이션에서 사용 (스프링 JPA 기본값)

@Transactional(isolation = Isolation.READ_COMMITTED)
public void readCommittedExample() {
    accountRepository.findBalanceById(1);
}

예제(Non-Repeatable Read 발생 가능)

  1. 트랜잭션 A가 계좌 잔액을 조회했을 때 1000원
  2. 트랜잭션 B가 1000원 → 500원으로 변경 후 COMMIT
  3. 트랜잭션 A가 다시 계좌를 조회하면 500원이 되어 있음 (이전과 값이 다름)

같은 데이터를 여러 번 조회할 때 값이 변할 수 있습니다. 이런 문제는 반복적으로 데이터를 조회하면서 수정을 하거나, 새로 입력하는 동작을 할 때 문제가 발생할 수 있으니 주의를 해야합니다. 제가 공부하면서 읽은 다른 블로그에서는 은행의 잔금조회와 잦은 송금이 동시에 발생하는 상황을 예로 들어주었습니다.


3. REPEATABLE READ (MySQL 기본 격리 수준)

트랜잭션이 시작될 때 조회한 데이터는 트랜잭션이 끝날 때까지 동일하게 유지됨

문제점: Phantom Read(팬텀 리드) 발생 가능

사용 예시: 온라인 뱅킹 같은 데이터 정합성이 중요한 경우

@Transactional(isolation = Isolation.REPEATABLE_READ)
public void repeatableReadExample() {
    accountRepository.findBalanceById(1);
}

예제(Phantom Read 발생 가능)

  1. 트랜잭션 A가 SELECT * FROM accounts WHERE balance > 1000; 실행
  2. 트랜잭션 B가 새로운 계좌를 추가하고 COMMIT
  3. 트랜잭션 A가 같은 SELECT 실행 시 새로운 행이 포함됨 (데이터 추가됨)

트랜잭션 내에서 동일한 데이터 조회 시 항상 같은 값이 보장됩니다. 값이 보장되는데 팬텀리드가 왜 생기느냐? 행이 추가되거나, 삭제되는 경우에 발생하는 것이 팬텀리드입니다. 같은 데이터를 조회하면 동일한 값을 보여주지만 예제와 같이 조회했을 때, 새로운 행이 포함되거나, 기존에 있던 행이 사라지는 경우가 발생합니다. 이를 팬텀리드라고 하는 것입니다.


4. SERIALIZABLE (가장 높은 격리 수준, 성능 저하 가능성 있음)

모든 트랜잭션을 순차적으로 실행 → 완벽한 데이터 일관성을 보장하지만 성능 저하 가능

문제점: 성능 저하 (트랜잭션이 직렬화되어 실행되기 때문)

사용 예시: 재고 관리, 금융 시스템과 같이 데이터 정합성이 최우선인 경우

@Transactional(isolation = Isolation.SERIALIZABLE)
public void serializableExample() {
    accountRepository.findBalanceById(1);
}

예제(완벽한 데이터 정합성 보장)

  1. 동시에 실행되는 트랜잭션이 없도록 강제
  2. 하나의 트랜잭션이 끝날 때까지 다른 트랜잭션이 대기
  3. Dirty Read, Non-Repeatable Read, Phantom Read 모두 방지됨

성능 저하가 크므로 대량의 동시 요청이 있는 환경에서는 비효율적입니다.


트랜잭션 격리 수준 비교

격리 수준 Dirty Read Non-Repeatable Read Phantom Read 성능 사용 예시
READ UNCOMMITTED O O O 🔥 빠름 거의 사용 안 함
READ COMMITTED O O ✅ 보통 기본값 (일반적인 애플리케이션)
REPEATABLE READ O ⚠️ 약간 느림 금융 거래, 주문 시스템
SERIALIZABLE ⛔️ 매우 느림 은행 시스템, 중요 데이터

일반적으로 READ COMMITED(기본값) 또는 REPEATABLE READ를 사용합니다.
데이터 정합성이 중요한 경우 SERIALIZABLE을 고려하되, 성능 저하를 주의해야 합니다.


스프링에서 트랜잭션의 격리 수준을 어떻게 조정하느냐에 따라 성능과 데이터 일관성이 크게 달라질 수 있습니다.

  • 성능이 중요하다면 READ COMMITTED(기본값) 사용하고
  • 데이터 정합성이 중요하다면 REPEATABLE READ 또는 SERIALIZABLE 고려해야 합니다.
  • READ UNCOMMITTED는 일반적으로 사용하지 않습니다.

각 애플리케이션의 요구사항에 맞는 격리 수준을 선택하여 안정적인 트랜잭션 관리를 수행할 수 있도록 조치하면 될 것 같습니다.

이 분이 그림도 그리고 더욱 잘 설명해주셨으니 더욱 궁금하시다면 방문해보시기 바랍니다. 참고로 MySQL기준입니다.
https://mangkyu.tistory.com/299

728x90

'개발자 공부 > Database' 카테고리의 다른 글

MySQL 2  (0) 2023.11.01
RDBS 및 MySQL 학습  (0) 2023.10.31
728x90

join

2개 이상의 테이블을 병합하는 명령어이다. inner join, left join, right join 3가지가 있으며, 개인적으로는 left join을 가장 많이 사용하여 inner join의 사용법을 잊어버렸었다. inner join의 경우에는 병합되는 테이블의 모두 있는 값들만 출력한다. 사용하기에 따라서는 left나 right보다 유용 할 수있다.

평소에는 join 시 On에  조건을 1가지만 입력했는데, 이번 강의에서 2개 이상을 입력하여 결합해보면서 결합조건에 대한 유연함을 얻을 수 있었다.


subquery

쿼리 안에 또다른 쿼리를 넣는 것을 서브쿼리라고 한다. 서브쿼리를 사용하면 쿼리 자체가 복잡해지는 단점이 있다. 하지만 서브쿼리를 사용하면서 다양한 방법으로 쿼리를 활용할 수 있다는 장점이 있다. 하지만 2개 이상의 서브쿼리를 사용하는 것은 지양하도록 하자. 생각보다 쿼리가 난잡해지는 단점이 있다.


union

join과는 다르게 서로 다른 테이블을 수직으로 병합하는 방법이다. union은 중복을 제거하고 병합하는 반면 union all을 사용하면 모든 데이터를 병합할 수 있다. 주의해야할 부분은 컬럼의 위치이다. union시 컬럼의 위치가 서로 다르거나 컬럼의 수가 일치하지 않아도 수직병합을 해버리기 때문에 데이터가 이상해질 수 있는 단점이 있으니 주의하도록 하자.

728x90

'개발자 공부 > Database' 카테고리의 다른 글

스프링 트랜잭션 격리 수준 (Isolation Level) 정리  (1) 2025.03.19
RDBS 및 MySQL 학습  (0) 2023.10.31
728x90

DATABASE

DATABASE란 데이터의 모음 또는 데이터베이스 관리시스템(DBMS)을 사용하는 데이터 저장소의 모음이다.
관계형 데이터베이스 중 가장 널리 쓰이는 MySQL의 강의를 했다.
MySQL의 문법자체를 난이도가 높지 않으나, 데이터를 설계한 경험이 부족하여 데이터를 어떻게 설계해야하는지에 대해 지식을 얻어가지 못하는 아쉬움이 있다. 이미 MySQL은 개인적으로 학습을 한 차례 했기 때문에 다시 해보는데 어려움은 없었으나, 부족한 시간에 많은 내용을 다루다 보니 진도가 매우 빠르게 진행되었다.

SQL공부 시 추천하는 사이트

https://opentutorials.org/course/3162

 

DATABASE1 - 생활코딩

수업소개 이 수업은 정보기술의 심장인 데이터베이스에 대한 포괄적인 소개를 담고 있습니다. 수업대상 이 수업은 구체적인 데이터베이스 제품을 다루지 않습니다. 데이터베이스라는 복잡한

opentutorials.org

참고 - datebase Ranking

https://db-engines.com/en/ranking

 

DB-Engines Ranking

Popularity ranking of database management systems.

db-engines.com

 

728x90

'개발자 공부 > Database' 카테고리의 다른 글

스프링 트랜잭션 격리 수준 (Isolation Level) 정리  (1) 2025.03.19
MySQL 2  (0) 2023.11.01

+ Recent posts