트랜잭션
- 데이터베이스에서 하나의 논리적 기능을 수행하기 위한 작업의 단위
- 여러 개의 쿼리들을 하나로 묶는 단위
- ACID 특징 : 원자성, 일관성, 독립성, 지속성
👉🏻 트랜잭션이란 데이터베이스의 상태를 변화시키기 위해 수행하는 작업의 논리적 단위
-> 데이터 베이스의 상태를 변화시킨다는 말은 SELECT, INSERT, UPDATE, DELETE 등과 같은 조작어를 사용하는 행동을 의미
- 트랜잭션은 데이터베이스 시스템에서 병행 제어 및 회복 작업 시 처리되는 작업의 논리적 단위이다.
- 사용자가 시스템에 대한 서비스 요구 시 시스템이 응답하기 위한 상태 변환 과정의 작업단위이다.
- 하나의 트랜잭션은 Commit 되거나 Rollback 된다.
원자성
-
트랜잭션과 관련된 일이 모두 수행되었거나 되지 않았거나를 보장하는 특징
-
문제가 발생하여 롤백하는 경우 그 이 후에 모두 수행되지 않음을 보장하는 것
-
트랜잭션 단위로 여러 로직들을 묶을 때, 외부 API를 호출하는 것이 있으면 안됨
-> 만약 있다면, 롤백이 일어났을 때 어떻게 해야 할 것인지에 대한 해결 방법이 있어야 하고, 트랜잭션 전파를 신경 써서 관리해야 함
예시
가정
- 1000만 원을 가진 홍철이가 0원을 가진 규영이에게 500만 원을 이체
과정
- 홍철의 잔고를 조회한다.
- 홍철에게서 500만 원을 뺀다.
- 규영에게 500만 원을 넣는다.
고려 사항
- 여기서 이 작업을 '취소'한다고 했을 때 홍철이는 다시 1000만 원. 규영이는 0원을 가져야 함
-> 홍철이는 500만 원, 규영이는 0원이 되지 않는 것을 의미합
-> 그래서 all or nothing
커밋과 롤백
커밋
- 여러 쿼리가 성공적으로 처리되었다고 확정하는 명령어
- 트랜잭션 단위로 수행되며, 변경된 내용이 모두 영구적으로 저장되는 것
- "커밋이 수행 되었다." == "하나의 트랜잭션이 성공적으로 수행되었다."

- 그림처럼 update, insert, delete의 쿼리가 하나의 트랜잭션 단위로 수행되고 이후에 데이터베이스에 영구 저장됩니다.
롤백
- 트랜잭션으로 처리한 하나의 묶음 과정을 일어나기 전으로 돌리는 일(취소)
👉🏻 이러한 커밋과 롤백 덕에 데이터의 무결성(정확성, 일관성, 유효성이 유지되는 것)이 보장
또한, 데이터 변경 전에 변경 사항을 쉽게 확인할 수 있고, 해당 작업을 그룹화 가능
트랜잭션 전파
- 트랜잭션을 수행할 때, 커넥션 단위로 수행하기 때문에 커넥션 객체를 넘겨서 수행해야 함
-> 하지만 매번 넘겨주기가 어렵기 때문에, 여러 트랜잭션 관련 메서드의 호출을 하나의 트랜잭션에 묶이도록 하는 것을 트랜잭션 전파라고 함
®Service
@Transactional (readOnly = true)
public class MemberService {
private final MemberRepository memberRepository;
public MemberService(MemberRepository memberRepository) {
this memberRepository = memberRepository;
}
- 코드처럼 Spring 프레임워크에서는 @Transactional 애너테이션을 통해 여러 쿼리 관련 코드들을 하나의 트랜잭션으로 처리
👉🏻 트랜잭션 전파란, 트랜잭션이 이미 진행 중일 때, 추가 트랜잭션을 수행하면 어떻게 동작할 지 결정하는 것을 의미
- 전파 종류에는 기존 트랜잭션과 별도로 추가 트랜잭션 실행하기나, 기존 트랜잭션을 이어 받아서 진행하기 등이 있음
일관성
- '허용된 방식'으로만 데이터를 변경해야 하는 것을 의미
- 데이터베이스에 기록된 모든 데이터는 여러 가지 조건, 규칙에 따라 유효함을 가져야 함
- ex) 계좌에 0원 있는데, 500원 이체 불가
격리성
- 트랜잭션 수행 시 서로 끼어들지 못하는 것
- 복수의 병렬 트랜잭션은 서로 격리되어, 마치 순차적으로 실행되는 것처럼 작동되어야 하고, 데이터베이스는 여러 사용자가 같은 데이터에 접근할 수 있어야 함
-> 그냥 순차적으로 하면 처리 시간이 오래걸려 성능이 나쁨
-> 완화된 격리 필요
-> 격리성은 여러 개의 격리 수준으로 나뉘어 격리성을 보장
격리 수준

- REPEATABLE_READ는 팬텀 리드,
READ_COMMITTED는 팬텀 리드, 반복 가능하지 않은 조회가 발생하며,
READ_UNCOMMITTED는 팬텀 리드, 반복 가능하지 않은 조회, 더티 리드가 발생할 수도 있음
격리 수준에 따라 발생하는 현상
팬텀 리드
- 한 트랜잭션 내에서 동일한 쿼리를 보냈을 때 해당 조회 결과가 다른 경우
- ex) 사용자 A가 age가 12 이상을 조회했을때 세 개의 테이블이 나왔지만, 그다음 사용자 B가 age가 15인 회원 레코드를 삽입하면 테이블이 4개로 바뀜
반복 가능하지 않은 조회
- 한 트랜잭션 내의 같은 행에 두 번 이상 조회가 발생했는데, 그 값이 다른 경우
- 예를 들어 사용자 A가 큰돌의 보석 개수가 100개라는 값을 가진 데이터였는데,
-> 그 이후 사용자 B가 그 값을 1로 변경해서 커밋했다고 하면
-> 사용자 A는 100이 아닌 1을 읽게 됩니다.
✚ 팬텀 리드와 반복 가능하지 않은 조회 차이점
반복 가능하지 않은 조회는 행 값이 달라질 수도 있는데, 팬텀 리드는 다른 행이 선택될 수도 있다는 것을 의미
더티 리드
- 반복 가능하지 않은 조회와 유사
- 한 트랜잭션이 실행 중일 때 다른 트랜잭션에 의해 수정되었지만, 아직 '커밋되지 않은' 행의 데이터를 읽을 수 있을 때 발생
- Write 작업이 이루어지고 있는 트랜잭션에 접근해서 발생한 문제
격리 수준
SERIALIZABLE
- 트랜잭션을 순차적으로 진행시키는 것
- 여러 트랜잭션이 동시에 같은 행에 접근할 수 없음
- 매우 엄격한 수준
- 교착 상태(꼬여서 둘 다 기다리는 상황)가 일어날 확률도 많고, 가장 성능이 떨어짐
REPEATABLE_READ
- 하나의 트랜잭션이 수정한 행을 다른 트랜잭션이 수정할 수 없도록 막아주지만, 새로운 행을 추가하는 것은 막지 않음
-> 따라서 이후에 추가된 행이 발견될 수도 있음
-> 수정 x, 추가 O
READ_COMMITTED
- 가장 많이 사용되는 격리 수준, MySQL8.0. PostgresSOL, SQL Server, 오라클에서 기본값으로 설정
- 커밋 완료된 데이 터에 대해서만 조회를 허용
- 어떤 트랜잭션이 접근한 행을 다른 트랜잭션이 수정할 수 있음
-> 이 때문에 트랜잭션이 다시 같은 행을 조회 시, 다른 내용이 발견 가능
READ_UNCOMMITTED
- 가장 낮은 격리 수준
- 하나의 트랜잭션이 커밋되기 이전에 다른 트랜잭션에 노출되는 문제가 있지만 가장 빠름 (다른 트랜잭션이 커밋하지 않은 정보는 읽을 수 있음)
-> 이는 데이터 무결성을 위해 되도록이면 사용하지 않는 것이 이상적이나, 몇몇 행이 제대로 조회되지 않더라도 괜찮은 거대한 양의 데이터를 '어림잡아 집계'하는 데는 사용하면 좋음
지속성
- 성공적으로 수행된 트랜잭션은 영원히 반영되어야 하는 것
- 이는 데이터베이스에 시스템 장애가 발생해도 원래 상태로 복구하는 회복 기능이 있어야 함을 뜻
- 데이터베이스는 이를 위해 체크섬, 저널링, 롤백 등의 기능을 제공
- 체크섬 : 중복 검사의 한 형태로, 오류 정정을 통해 송신된 자료의 무결성을 보호하는 단순한 방법
- 저널링 : 파일 시스템 또는 데이터베이스 시스템에 변경 사항을 반영(commit)하기 전에 로깅하는 것, 트랜잭션 등 변경 사항에 대한 로그를 남기는 것
무결성
- 데이터의 정확성, 일관성, 유효성을 유지하는 것
- 무결성이 유지되어야 데이터베이스에 저장된 데이터 값과 그 값에 해당하는 현실 세계의 실제 값이 일치하는지에 대한 신뢰가 생김
- 무결성의 종류
