-
면접대비: 트랜잭션에 대해서 설명해주세요.Back-end 2026. 6. 4. 01:02728x90
기본뜻
트랜잭션(Transaction)은 데이터베이스 관리에서 ‘쪼갤 수 없는 최소한의 업무 처리 단위’를 말합니다. 한 번에 성공적으로 수행되어야 할 일련의 연산들을 묶어놓은 것으로, 데이터의 무결성과 정합성을 유지하는 데 사용됩니다.
주요 명령어
- Commit: 트랜잭션의 모든 작업이 성공적으로 처리되어 데이터베이스에 영구적으로 반영하는 명령어입니다.
- Rollback: 작업 도중 오류가 발생했을 때, 트랜잭션이 시작되기 전의 상태로 모든 과정을 되돌리는 명령어입니다.
트랜잭션의 4대 핵심 속성 (ACID)
- 원자성(Atomicity): all or nothing
- 일관성(Consistency): 무결성보장
- 고립성(Isolation): 트랜잭션은 독립적이어야 하고, 서로 영향을 주고 받으면 안된다.
- 지속성(Durability): 성공적으로 수행된 트랜잭션결과는 영구적으로 저장되어야 한다.
트랜잭션의 고립(격리)수준 (isolation level)
아래로 갈수록 격리 수준이 높아집니다.
- READ-UNCOMMITTED(커밋되지 않은 읽기)
- 특정 트랜잭션에서 변경은 했지만 아직 커밋되지 않은 데이터를 다른 트랜잭션에서 읽을 수 있는 레벨
- 이 상황을 Dirty Read라고 하며 문제가 된다.
- READ-COMMITTED(커밋된 읽기)
- 커밋이 된 데이터만 다른 트랜잭션에서 읽을 수 있는 레벨
- Dirty Read 문제는 해결된다.
- Non-Repeatable-Read 문제가 있다: 같은 트랜잭션에서 여러번 같은 데이터를 조회 할때 서로 다른 값이 나올 수 있는 현상
- A 트랜잭션에서 데이터를 읽은 후에 B 트랜잭션에서 같은 데이터를 수정후 커밋함 → 그후 A 트랜잭션에서 동일 데이터를 다시 읽으면 B 트랜잭션이 커밋한 데이터를 보게 되므로 처음 조회 할때와 다른 데이터를 보게 된다.
- REPEATABLE-READ(반복 가능한 읽기)
- 특정 데이터를 반복 조회 해도 같은 값을 보장 받을 수 있는 레벨
- Non-Repeatable-Read 문제를 해결한다.
- Phantom-Read 문제가 있다: 한 트랜잭션에서 동일한 쿼리를 여러번 실행했을때 다른 트랜잭션에 의해 새로운 데이터가 삽입, 삭제되었을때 결과가 달라지는 현상
- repeatable-read 레벨이 다른 트랜잭션에 의해 수정된 데이터를 수정되기 전 버전으로 볼 수 있도록 보장하지만, 신규 데이터나 삭제된 데이터까지 보장해주진 않는다.
- SERIALIZABLE(직렬화 가능)
- 순차적으로 트랜잭션이 수행되는것 처럼 동작하는 레벨
- 가장 엄격한 격리 수준으로 동시성과 성능이 가장 낮음
mysql 은 기본값이 REPEATABLE-READ 레벨이고 일반적인 다른 RDB 는 READ-COMMITTED 가 기본 레벨이다.
(하지만 mysql 은 repeatable-read 레벨에서도 Phantom-read 현상은 발생하지 않는다고 함)더 높은 레벨의 격리 수준을 기본값으로 사용하지 않는 이유:
serializable 레벨이 성능 오버헤드가 꽤 크기도 하지만 실제 비즈니스로직에서 Phantom-read까지 막을 필요가 없는 경우가 대부분이다. 모든 트랜젝션이 serializable 레벨까지 필요없다는 경험적 사실이 있고, 어플리케이션로직 + 보정 절차로 충분히 안전하게 운영가능하다는게 업계 표준이다. 금융/트레이딩 같은 직렬성이 필수인 영역에서도 serializable 레벨의 성능문제등으로 에플리케이션 레벨 에서 락, 큐 등으로 구현하는 경우가 더 많음
Non-Repeatable-Read(같은 행을 두번 읽었는데 값이 달라짐) 문제도 분명 조심해야할 부분이 있음.
트랜잭션1과 트랜잭션2 에서 각각 같은 행을 select 한 후에 둘다 update 를 하면 이전 커밋한 내용이 덮어써져 버리게 된다. 이와 같은 계산 후 반영 패턴(select → 계산 → update)이 위험하다.
해결법은 1. 낙관적락 혹은 2. 비관적락 사용 또는 3. update 시 계산을 쿼리로 처리(읽어서 그값 기반으로 변경을 가하면 덮어써질 수 있기때문에..)낙관적락(Optimistic Locking)
각 레코드에 버전관리 칼럼(version)을 두는 방식. select 할때 version 칼럼도 가져와서 수정후 저장하는 시점에 db 에 저장되어 있는 버전값이 여전히 같아야만 update 를 실행한다. 저장하면서 version 을 1 증가 시킨다.
낙관적이라고 하는 이유는 동시 갱신이 거의 발생하지 않을 것이라는 전제를 가지고 사용하는 방식이기때문이다. 만약 데이터를 읽고 수정후에 저장하려고 할때 이미 해당 레코드의 버전이 바뀐 상태라면 해당 트랜잭션은 실패 처리가 된다. 이경우 어플리케이션에서 에러 처리를 통해 재시도를 해주어야 한다.
낙관적락은 분산환경에서 사용하기 적당하다.
낙관적락은 충돌이 거의 없는 경우에 유리하다. 트랜잭션간 동시쓰기 현상이 자주 발생하는 경우에는 에러발생, 재시도 요청이 많아지면서 성능 저하가 발생할 수 있기때문이다. 이경우는 비관적락이 더 적당하다.비관적락(pessimistic Locking)
여러 트랜잭션이 같은 데이터를 동시갱신하는 현상이 자주 일어날것이라는 전제로 사용하는 방식이다.
단순히 낙관적락을 안쓰는 것이 비관적락을 사용하는 것은 아니다. 트랜잭션의 격리수준(isolation level)과도 관계가 없다.
쿼리를 통해 DB의 락 메커니즘을 명시적으로 지정해야 비관적락을 사용하게 된다.- 공유락: SELECT … LOCK IN SHARE MODE (MySQL) - 여러 트랜잭션이 동시에 읽을 수 있지만, 쓰기는 불가.
- 베타락: SELECT … FOR UPDATE - 다른 트랜잭션은 읽기도/쓰기도 대기 상태.
충돌이 잦을 때 사용하기 적절하다.
참고: 비관적락은 행(row) 단위 혹은 범위 단위로 동작한다. 따라서 서로 다른 트랜잭션이 서로 다른 테이블의 행을 잠근 경우에는 동시실행이 가능하다.
비관적락이 필요한 시나리오
재고 관리/티켓 예매(희소자원을 동시에 차감해야 하는 경우. 낙관적락을 사용하면 재시도 폭증), 은행 계좌 출금/이체, 설문 참여 제한, 중복 응모 방지,트랜잭션의 격리 수준은 읽기 관점에서의 제어 방법이고 쓰기 관점의 충돌은 낙관적락이나 비관적락 같은 방법으로 해결해야 한다.
참고
https://chatgpt.com/g/g-p-68c904e6f32c8191915290f0c9ad1309/c/68c8c591-0bd8-8328-88d6-a237ed104291
https://developer-jinnie.tistory.com/31#:~:text=Phantom-Read&text=팬텀 리드란 Non-Repeatable,가 사라지는 문제를 말한다'Back-end' 카테고리의 다른 글
java bean mapper와 DTO 소개 (0) 2018.03.19 spring-data-jpa + querydsl 로 개발하기 - 2 (3) 2016.07.28 spring-data-jpa + querydsl 로 개발하기 - 1 (2) 2016.06.08 webSocket 으로 개발하기 전에 알고 있어야 할 것들 (6) 2015.10.22 thymeleaf inline javascript 사용하기 & jackson json 으로 변환하기 (0) 2015.04.25