콘텐츠로 이동

트랜잭션과 무결성

트랜잭션과 무결성

참고: https://papimon.tistory.com/89

트랜잭션

  • 일관성 있고 신뢰할 수 있는 방식으로 독립적이게 처리되는 "작업 단위"
    • 예상치 못한 에러가 발생해도 데이터베이스를 신뢰성있는 상태로 만들 수 있도록 하는 "작업 단위"
  • 데이터베이스의 변화를 나타냄
    • All or Nothing
  • Commit: 변경된 내용이 모두 영구적으로 저장되는 것
  • Rollback: 트랜잭션으로 처리한 하나의 묶음 과정을 일어나기 전으로 돌리는 일
  • ACID
    • Atomicity - 원자성
      • 트랜잭션 내의 모든 연산은 완벽하게 수행될 것
      • 어느 하나가 오류나면 전체 취소될 것
      • 모두 반영되기(Commit) or 전혀 반영되지 않기(Rollback)
    • Consistency - 일관성
      • 트랜잭션은 "허용된 규칙" 안에서만 데이터를 변경할 수 있음
        • 허용된 규칙: PK/FK, Cascade, 트리거 등
    • Isolation - 독립성
      • 트랜잭션 수행 시 다른 트랜잭션의 연산 작업이 중간에 끼어들지 못하도록 방지하는 것
    • Durability - 지속성
      • 성공적으로 완료된 트랜잭션은 시스템이 고장나더라도 영구적으로 반영될 것
  • ACID를 고려하여 트랜잭션 범위 정하기
    • Atomicity: 하나의 로직 내에서 변화가 필요한 모든 연산은 하나의 트랜잭션으로!
    • Consistency: 데이터베이스에서 정의한 규칙 준수
    • Isolation: 해당 작업 어느 수준까지 독립시킬 것인지 결정
    • Durability: 트랜잭션의 기록을 SSD/HDD에 저장하는 것 (이건 벤더가 알아서)

스프링에서의 트랜잭션

  • @Transactional : 선언적 트랜잭션 with AOP
    • 핵심 비즈니스 로직 안 건드리면서 트랜잭션 사용가능

트랜잭션 전파 설정

  • 진행 중인 트랜잭션에서 다른 트랜잭션 호출 시, 어찌 처리할건지!
    • [REQUIRED(default)]
      • 부모 트랜잭션 있다면 거기에 합류
      • 부모 트랜잭션 없다면 새로운 트랜잭션 생성
      • 하나의 트랜잭션으로 묶이기에 롤백 시 모든 진행 상황 롤백됨
    • [REQUIRES_NEW]
      • 무조건 새로운 트랜잭션 생성!
      • 각각 트랜잭션 롤백되더라도 영향 없음
    • [MANDATORY]
      • 부모 트랜잭션에 합류
      • 부모 트랜잭션 없다면 예외 발생
    • [NESTED]
      • 부모 트랜잭션 존재시 중첩 트랜잭션 생성
      • 부모 트랜잭션 없다면 새로운 트랜잭션 생성
      • 중첩된 트랜잭션 내부에서 롤백 시, 중첩 트랜잭션 시작까지만 롤백
      • 중첩 트랜잭션은 부모 트랜잭션 커밋 시 같이 커밋!
    • [NEVER]
      • 트랜잭션 생성 안 함
      • 부모 트랜잭션 존재 시 예외 발생
    • [SUPPORTS]
      • 부모 트랜잭션 있다면 합류
      • 부모 트랜잭션 없다면 트랜잭션 생성 X
    • [NOT_SUPPORTED]
      • 부모 트랜잭션 있다면 보류
      • 부모 트랜잭션 없다면 트랜잭션 생성 x

트랜잭션 고립 수준

  • 동시에 여러 트랜잭션 처리될 때, 트랜잭션끼리 얼마나 고립되어 있는지
    • [DEFAULT(default)]
      • DB 벤더사의 고립 수준 정책 따름
      • Oracle: READ_COMMITTED
      • MySQL: REPEATABLE_READ
    • [READ_UNCOMMITTED]
      • 트랜잭션 1이 커밋하지 않은 데이터에 대해, 트랜잭션 2가 읽는 것을 허용 => 잘 안써 너무 빡세 문제들이
    • [READ_COMMITTED]
      • 트랜잭션 1이 커밋한 데이터에 대해, 트랜잭션 2가 읽는 것을 허용
    • [REPEATABLE_READ]
      • 트랜잭션 1이 읽은 데이터에 대해 트랜잭션 1이 종료될 때 까지, 다른 트랜잭션에서 수정/삭제 허용 X
        • 데이터 삽입은 가능
    • [SERIALIZABLE]
      • 트랜잭션 1이 읽은 데이터에 대해 트랜잭션 1이 종료될 때 까지, 다른 트랜잭션에서 수정/삭제/삽입 허용 X
  • 문제점
    • [READ_UNCOMMITTED] - 동시성 MAX | 격리성 MIN
      • 팬텀 리드
      • 반복 가능하지 않은 조회
      • 더티 리드
        • 한 트랜잭션이 실행 중일 때 다른 트랜잭션에 의해 수정되었지만 커밋 되기도 전에 읽어버림
    • [READ_COMMITTED]
      • 팬텀 리드
      • 반복 가능하지 않은 조회: 한 트랜잭션 내의 같은 행에 두 번 이상의 조회 발생했는데, 그 값이 다른 경우
        • 트랜잭션 A에서 보석 100개 가지고 있다고 조회
        • 트랜잭션 B에서 보석 1개 가지고 있다고 변경
        • 트랜잭션 A에서 보석 1개 가지고 있다고 조회
    • [REPEATABLE_READ] --- MySQL
      • 팬텀 리드: 한 트랜잭션 내에서 동일한 쿼리 보냈을 때 조회 결과가 다른 경우
      • Repeatable-read는 트랜잭션1에서 읽은 데이터에 대해 트랜잭션2가 삽입할 수 있게 허용하잖아?
        • 그러다 보니까 트랜잭션2 나오기 전에 읽었던 데이터 != 트랜잭션 2 발생후 데이터가 될 수 있다는 것이지
        • 다른 행이 선택될 수도 있다~
    • [SERIALIZABLE] - 동시성 MIN | 격리성 MAX