[DB] 트랜잭션과 무결성

뚜비·2023년 7월 25일
0

DB

목록 보기
3/6

트랜잭션

  • DB에서 하나의 논리적 기능을 수행하기 위한 작업의 단위
    여러 개의 쿼리들을 하나로 묶는 단위
  • ACID(원자성, 일관성, 독립성, 지속성) 특징을 가짐


원자성(atomicity)

all for nothing

  • 트랜잭션과 관련된 일이 모두 수행되었거나 되지 않았음을 보장
    EX) 트랜잭션을 commit → 문제발생, rollabck → 모든 작업이 수행되지 않음을 보장 (아래 시나리오를 참고!)
  • 트랜잭션 단위로 여러 로직들을 묶을 때 외부 API를 호출하는 것이 있으면 안 됨
    → 만약 있다면 롤백이 일어났을 때 해결방법이 존재해야 하고 트랜잭션 전파 신경 써서 관리

시나리오

  • 상황) 1000만 원을 가진 홍철이가 0원을 가진 규영이에게 500만원을 이체
    결과) 홍철이는 500만원 규영이는 500만을 가진다.

✅ 해당 결과는 다음과 같은 operation 단위로 이루어진 과정을 거친다.

1. 홍철의 잔고를 조회 
2. 홍철에게서 500만 원을 뺀다.
3. 규영에게 500만 원을 넣는다. 

  • 상황) 이 때 작업을 '취소'
    결과) 홍철이는 1000만원 규영이는 0원을 가져야 함
    ✅ 즉 2번 작업까지 진행되었다가 취소해도 홍철이는 500만원, 규영이는 0원이 되지 않는다.
    ✅ all for nothing

commit과 rollback

commit과 rollback을 통해 데이터의 무결성이 보장

  • commit
    : 여러 쿼리가 성공적으로 처리되었다고 확정하는 명령어
    : 트랜잭션 단위로 수행되며 변경된 내용이 모두 영구적으로 저장
    : "commit이 수행되었다." == "하나의 트랜잭션이 성공적으로 수행되었다."
    : TRANSACTION(INSERT, UPDATE, DELETE)작업 내용을 실제 DB에 저장한다.
    : 이전 데이터가 완전히 UPDATE되고 모든 사용자가 변경한 데이터의 결과를 볼 수 있다.


위의 그림은 UPDATE, DELETE, INSERT 쿼리가 하나의 트랜잭션 단위로 수행되고 이후에 DB에 영구저장


  • rollback
    : 트랜잭션으로 처리한 하나의 묶음과정을 일어나기 전으로 돌리는 일(취소)
    : 에러나 여러 이슈 때문에 트랜잭션 전으로 돌려야 할 때
    : TRANSACTION(INSERT, UPDATE, DELETE)작업 내용을 취소
    : 이전 COMMIT한 곳까지만 복구한다.


현재 문제가 발생한 트랜잭션을 취소하면 된다.



트랜잭션 전파

🤔 잠깐! 트랜잭션의 시작과 끝
트랜잭션의 시작지점과 끝나는 지점이 존재한다.

  • 시작지점
    : 트랜잭션은 하나의 Connection 객체를 가져와 사용하다가 닫는 사이에서 일어남. 트랜잭션의 시작과 종료는 Connection 단위로 수행하기 때문
    : 1개의 트랜잭션을 사용한다는 것은 하나의 커넥션 객체를 사용한다는 것
  • 끝지점
    : 하나의 트랜잭션이 시작지면 commit() 또는 rollback() 호출될 때 까지가 하나의 트랜잭션으로 묶인다
  • 트랜잭션 전파
    : 기존에 트랜잭션이 진행중일 때 추가적인 트랜잭션을 진행해야 하는 경우가 존재, 이미 트랜잭션이 진행중일 때 추가 트랜잭션 진행을 어떻게 할지 결정하는 것이 전파 속성(Propagation)
    : 여러 트랜잭션 관련 메서드의 호출을 하나의 트랜잭션에 묶이도록 하는 것 → 이를 매번 넘겨주기 어렵기 때문에 넘겨서 수행하지 않음

EX) Spring 프레임워크에서는 @Transactional을 통해 여러 쿼리 관련 코드를 하나의 트랜잭션으로 처리

@Service 
@Transactional(readOnly =true)
public class MemberService{
	private final MemberRepository memberRepository;
    
    public MemberService(MemberRepository memberRepository){
    	this.memberRepository = memberRepository;
    }
}

위의 그림은 transcation propagation의 디폴트 처리법이다.



일관성(consistency)

  • 허용된 방식으로만 데이터를 변경해야 하는 것을 의미
  • 데이터베이스에 기록된 모든 데이터는 여러가지 조건, 규칙에 따라 유효함을 가져야 함
    EX) 홍철이는 1000만 원이 있고 범석이는 0원이 있음
    -> 현재 상황에서 범석이가 홍철이한테 500만 원 입금 가능? NO 불가능
    -> 0원이므로 500만 원 나오는 것이 불가능! (마이너스 통장 제외)


독립성(or 격리성, isolation)

  • 트랜잭션 수행 시 서로 끼어들지 못하는 것
  • 복수의 병렬 트랜잭션은 서로 격리되어 마치 순차적으로 실행되는 것처럼 작동되어야 함
  • DB는 여러 사용자가 같은 데이터에 접근할 수 있어야 함
  • 그.러.나. 순차적으로 하면 쉽지만 성능이 떨어짐 ㅠㅠ

Isolation level

  • 격리수준
    : READ_UNCOMMITTED로 갈수록 동시성은 강한데 격리성이 약해지고 SERIALIZABLE로 갈수록 동시성은 약해지고 격리성은 강해짐

1. SERIALIZABLE

  • 트랜잭션을 순차적으로 진행시키는 것
  • 여러 트랜잭션이 동시에 같은 행에 접근할 수 없음
    → 해당 행에 격리시키고 이후 트랜잭션이 이 행에 대해 접근이 일어나야 한다면 기다려야 함
    팬텀 리드, 반복 가능하지 않은 조회, 더티 리드가 발생하지 않음
  • 격리성이 높고 동시성이 낮아 매우 엄격한 수준
  • 교착 상태가 일어날 확률이 많고 가장 성능이 떨어지는 격리 수준

2. REPEATABLE_READ

  • 하나의 트랜잭션이 수정한 행을 다른 트랜잭션이 수정할 수 없도록 막아주지만 새로운 행을 추가하는 것은 막지 않음
  • 이후에 추가된 행이 발견될 수 있음
    팬텀 리드가 발생할 수 있음

3. READ_COMMITTED

  • 가장 많이 사용되는 격리 수준
  • MySQL, PostgreSQL, SQL Server, 오라클에서 default
  • READUNCOMMITTED와 달리 다른 트랜잭션이 commit하지 않은 정보는 읽을 수 없음
    → 즉
    commit 완료가 된 데이터에 대해서만 조회_ 허용
  • 어떤 트랜잭션이 접근한 행을 다른 트랜잭션이 수정할 수 있음
    팬텀 리드반복 가능하지 않은 조회가 발생

4. READ_UNCOMMITTED

  • 하나의 트랜잭션이 커밋되기 이전에 다른 트랜잭션에 노출되는 문제가 있지만 가장 빠르다
  • 가장 낮은 격리수준을 가짐
    팬텀 리드, 반복 가능하지 않은 조회, 더티 리드가 모두 발생
  • 데이터 무결성을 위해 되도록 사용하지 않는 것이 이상적, 거대한 양의 데이터를 '어림잡아' 집계하는데 사용하면 좋다.


  • 각 격리 수준에 따라 발생하는 현상

    People table을 통해 격리 수준에 따라 발생하는 현상을 이해해보자.

1. Phantom read(팬텀 리드)

  • 한 트랜잭션 내에서 동일한 쿼리를 보냈을 때 해당 조회 결과가 다른 경우

-> Transaction 1은 People 테이블에서 salary가 250 이하인 row를 조회한다. 조건을 만족 시키는 row 2개가 출력된다.
-> Tansaction 2는 People 테이블에 (3, Jacob, 120)이라는 row를 추가한다. 이떄 해당 row는 Transaction 1의 조건을 만족시킨다.
-> 이후 Transcation 1이 People 테이블에서 salary가 250 이하인 row를 조회한다. 조건을 만족시키는 row 3개가 출력됨으로써 앞의 결과와 다르게 나온다.


2. Repeatable read(반복 가능하지 않은 조회)

  • 한 트랜잭션 내의 같은 행에 두 번 이상 조회가 발생했는데, 그 값이 다른 경우

    -> Transcation 1은 People table에서 id가 1인 salary를 조회한다. 결과로 150을 얻는다.
    -> Transcation 2는 People table에서 id가 1d인 salary 값을 180으로 업데이트하고 commit 한다.
    -> 이후 Transaction 1은 People table에서 id가 1인 salary를 조회한다.결과로 150이 아닌 180을 읽게 된다.

🤔 Phantom read와 차이점
Repeatable read : 조회 시 row 값이 달라질 수도 있음
Phantom read : 조회 시 다른 row가 선택될 수도 있음


3. Dirty read(더티 리드)

  • Repeatable read와 유사하며, 한 트랜잭션이 실행 중일 때 다른 트랜잭션에 의해 수정되었지만 아직 commit되지 않은 행의 데이터를 읽을 수 있을 때 발생


-> Transaction 2는 People 테이블의 id가 1인 salary 값을 180으로 업데이트한다.
-> Transaction 1은 id가 1인 salary 값을 조회한다. 결과로 150이 아닌 180을 얻는다.
-> 아직 Transcation 2가 commit 하지 않은 값을 읽었으므로 rollback 한다. 왜냐하면 Transaction 1은 아직 database에 존재하지 않은 값을 읽었기 때문이다.



지속성(durability)

  • 성공적으로 수행된 트랜잭션은 영원히 반영되어야 하는 것
  • DB에 시스템 장애가 발생해도 원래 상태로 복구하는 회복 기능이 있어야 함
  • DB는 이를 위해 체크섬, 저널링, 롤백 등의 기능을 제공

1. 체크섬
: 중복 검사의 한 형태
: 오류 정정을 통해 송신된 자료의 무결성을 보호하는 단순한 방법

2. 저널링
: 파일 시스템 또는 데이터베이스 시스템에 변경 사항을 commit하기 전에 로깅하는 것
: 트랜잭션 등 변경사항에 대한 로그를 남기는 것



무결성

  • 무결성 : 데이터의 정확성, 일관성, 유효성을 유지하는 것
  • 무결성이 유지되어야 DB에 저장된 데이터 값과 그 값에 해당하는 현실 세계의 실제 값이 일치하는지에 대한 신뢰 생김
이름설명
개체 무결성기본키로 선택된 필드는 빈 값을 허용하지 않음
참조 무결성서로 참조 관계에 있는 두 테이블의 데이터항상 일관된 값을 유지해야 함
고유 무결성특정 속성에 대해 고유한 값을 가지도록 조건이 주어진 경우 그 속성 값은 모두 고유한 값을 가짐
NULL 무결성특정 속성 값에 NULL이 올 수 없다는 조건이 주어진 경우 그 속성 값은 NULL이 될 수 없다는 제약 조건


😎참고자료

면접을 위한 CS전공지식
예제로 배우는 Oracle
[Spring] 트랜잭션의 전파 설정별 동작
[Spring] 스프링의 트랜잭션 전파 속성(Transaction propagation) 완벽하게 이해하기
Transaction Propagation
Transaction Levels

profile
SW Engineer 꿈나무 / 자의식이 있는 컴퓨터

0개의 댓글