티스토리 뷰

Web/정리글

DB 트랜잭션 정리

구름뭉치 2021. 10. 4. 18:12

트랜잭션이란?

데이터베이스 관리 시스템 (DBMS)에서 DB의 상태를 변화시키는 작업의 논리적 최소 단위를 의미한다.

 

트랜잭션 특징 : ACID

Atomicity

  • 원자단위로서 더이상 쪼갤 수 없는 논리적 최소 단위임을 말한다.
  • 예를 들어 계좌이체를 하는 경우 송금/입금이 존재하는데 두 작업은 쪼갤 수 없다는 것이다. 송금이 성공하고 입금이 실패하는 트랜잭션은 존재하지 않도록 하는 것이 목적.

Consistency

  • 트랜잭션이 성공했다면 데이터베이스는 항상 일관성 있는 상태로 유지 되어야 하는 것을 말한다.
  • 만약 도메인 무결성 제약조건이 잔고는 0미만이 될 수 없다는 것이라면 이를 위반하는 트랜잭션은 존재할 수 없는 것이다.

Isolation

  • 트랜잭션을 수행중에 다른 트랜잭션이 끼어들 수 없음을 말한다.
  • 송금/입금 트랜잭션이 nested되어 실행될 경우 post 트랜잭션이 pre 트랜잭션의 커밋 전에 잔고를 보고 송금을 진행했지만 post 커밋 시점에는 pre 트랜잭션의 커밋으로 잔고가 0원이 되어 중단될 수 있다.
  • 이러한 트랜잭션 격리 수준은 4단계로 나뉜다. (Isolation Level)

Durability

  • 성공적으로 수행된 트랜잭션은 영구적으로 적용되어야 함을 말한다.

 

트랜잭션의 격리

트랜잭션 간 서로 중첩이 자유롭다면 온전한 데이터를 얻는게 힘들것이고 완전 배타적으로 작동된다면 동기적으로 수행되어 성능상에서 불이익을 얻을 수 있다. 이러한 접근 제어를 위해 사용되는 것이 LOCK이다.

 

LOCK : 트랜잭션의 동시성 제어를 위한 락

Shared Lock (Read Lock), 공유락

  • 데이터를 읽을 때 사용되는 Lock이다.
  • 공유 락은 공유 락끼리 동시에 접근이 가능하다.
    • 운영체제에서 Readers-Writers Problem 와 비슷하다. Write는 불허하고, Read는 해당 Critical Section에
      접근이 허용된다는 것이다.
    • Read Lock은 Read에게만 열려있는 Lock인 것.
  • 공유 락이 설정된 데이터에 배타 락을 적용할 수 없다. 따라서 공유락이면 공유락이지 배타락일 순 없다.

T1이 r 행에 대한 s Lock을 갖고 있을 경우 (T : 트랜잭션, s : shared lock, x : exclusive lock)

  • T2가 s Lock을 요청할 경우 즉시 승인된다. 결과적으로 T1, T2 둘다 r 행에 대해 s Lock을 갖게 된다.
  • 반면에 T2가 x Lock을 요청한다면 T1이 해당 r행의 s Lock을 풀 때까지 기다려야 한다.

 

Exclusive Lock (Write Lock), 배타락

  • 데이터를 변경할 때 사용되는 Lock이다.
  • 트랜잭션이 완료 될 때까지 유지된다.
  • Lock이 해제 될 때 까지 다른 트랜잭션(조회 포함)은 해당 리소스에 접근이 불가능하다.

T1이 r 행에 대한 x Lock을 갖고 있을 경우 (T : 트랜잭션, s : shared lock, x : exclusive lock)

  • T2는 x Lock을 갖고 있어도 참여할 수 없다. T1이 r 행에 대한 Lock을 풀 때까지 기다려야 한다.

 

트랜잭션 격리 수준

1. READ UNCOMMITTED (LEVEL 0)

  • 사실상 격리가 없다고 봐야하며 대부분의 동시 접근을 허용한다.
    이로 인해 Dirty read, Non Repeatable read, Phantom read가 모두 발생할 수 있으며
    이로인해 같은 쿼리를 다시 수행해도 다른 결과를 얻을 수 있다. -> DB 일관성 유지가 불가능하다.
  • SELECT 쿼리가 수행되는 동안 해당 데이터에 Shared Lock이 걸리지 않는 단계.
  • 트랜잭션에서 처리중이거나, 아직 Commit 되지 않은 데이터를 다른 트랜잭션에서 읽는 것을 허용한다.

Dirty read 문제

  1. A 트랜잭션에서 회원 A의 구매 목록을 추가하여 결제금액이 4 -> 5만원으로 변경
  2. 아직 Commit 하지 않음
  3. B 트랜잭션에서 회원 A의 결제금액을 조회
  4. 결제금액이 5만원으로 조회된다
    • -> 이를 Dirty read라고 한다.
  5. A 트랜잭션에서 문제가 발생하여 Rollback 처리, 결제금액도 다시 4만원으로 변경됨
  6. B 트랜잭션은 조회한 5만원을 가지고 그대로 진행

결과적으로 데이터 정합성의 문제가 생긴다.

 

2. READ COMMITTED (LEVEL 1)

  • SELECT 쿼리가 수행되는 동안 해당 데이터에 Shared Lock이 걸리는 단계.
  • 트랜잭션의 변경내용이 Commit이 완료된 경우에만 다른 트랜잭션에서 조회가 가능하다.
  • Dirty read를 방지한다. 하지만 Non Repeatable read, Phantom read는 여전히 발생한다.
  • 동시 Transaction에서 Commit 되지 않은 변경은 영향을 주지 않게 되었다.
    하지만 Commit이 되면 다시 읽었을 때 결과값이 변경될 수 있다.

Non Repeatable Read 문제

  • B 트랜잭션에서 회원 A의 결제금액을 조회
  • 4만원이 조회됨
  • A 트랜잭션에서 회원 A의 결제금액을 4 -> 5만원으로 변경하고 Commit
  • B 트랜잭션에서 회원 A의 결제금액을 다시 조회
  • 5만원이 조회됨

이는 하나의 트랜잭션내에서 똑같은 SELECT를 수행했을 경우 같은 결과를 반환해야 한다는 Repeatable Read 정합성에 어긋나는 결과를 가져온다.

 

만약 입금/출금이 이뤄지는 트랜잭션이 존재하고 회원의 당일 입금 총액을 보여주는 트랜잭션이 있다고 하면, 입금 총액을 조회할 때마다 다른 결과를 가져오게 된다.

 

 

3. REPEATABLE READ (LEVEL 2)

  • 트랜잭션이 완료 될 때까지 SELECT 쿼리가 사용되는 모든 데이터에 Shared Lock이 걸리는 단계.
  • 이때 Lock은 조회 조건에 따라 달라질 수 있다.
    • 특정 행만 조회하는 unique index 또는 unique search 조건을 사용하는 경우 InnoDB는 해당 index record만 Lock하게 된다.
    • 그렇지 않은 조건의 경우 InnoDB는 검색된 범위의 인덱스에 대해 Lock을 걸게 된다. (gap lock 또는 next-key lock)
    • 이렇게 함으로서 해당 범위내로의 삽입을 막는다.
  • 트랜잭션이 시작되기 전에 커밋된 내용에 대해서만 조회할 수 있다.
  • 트랜잭션이 범위 내에서 조회한 데이터 내용이 항상 동일함을 보장한다. 단, 범위 쿼리를 다시 실행하면 새로 추가된 행이나 제거된 행이 생길 수 있다.
  • 다른 사용자는 트랜잭션 영역에 해당되는 데이터에 대해서 수정이 불가능하다.
  • Phantom Read 문제가 발생할 수 있다.

Non Reapeatable read 문제 해결

  1. A 트랜잭션이 3번 회원을 조회
  2. B 트랜잭션이 3번 회원의 이름을 변경하고 커밋완료 함
  3. A 트랜잭션에서 3번회원을 다시 조회
  4. Undo 영역에 백업된 데이터를 반환. 변경되기 전 이름을 봄

즉, 자신의 트랜잭션 번호보다 낮은 트랜잭션 번호의 변경 & 커밋만 보는 것이다.

  • 회원 A가 장바구니에 구매 목록을 담았다.
  • 회원 A가 결제하기 위해 결제금액을 조회 -> 4만원
  • 회원 A가 장바구니에 물건을 추가 -> 5만원
  • 회원 A의 결제금액 -> 4만원만 결제됨. 나중에 담은 것은 결제를 위한 조회 이전에 발생된 것으로 취급하지 않는다.

 

Phatom read 문제

  • Phantom = 유령을 말한다.
  • 하나의 트랜잭션 내에서 같은 쿼리를 두번 실행했는데 첫번째 쿼리에는 없는 레코드가 두번째 쿼리에서 나타나는 현상.
    (유령 레코드)
  • Repeatable read 이하 계층에서만 발생하며 INSERT에 대해서만 발생하는 문제이다.
문제 상황
start transaction; -- transaction id = 1
select * from customer; -- 0건 조회

    start transaction; -- transactionid = 2
    insert into customer values(1, 'woonsik', 27);
    commit;

select * from customer; -- 0건 조회, REPEATABLE READ 단계이므로 자신보다 낮은 트랜잭션의 변경에만 영향을 받는다.
update customer Set name = 'handsome woonsik' where id = '1'; -- 1 row updated
select * from customer; -- 1건 조회
commit;

앞선 트랜잭션이 추후 트랜잭션에 영향을 받지 않아야 하는데 INSERT가 발생하고 UPDATE 시 조회되지 않던 row가 조회되는 일이 발생한다.

 

4. SERIALIZABLE (LEVEL 3)

  • 매우 엄격한 격리 수준이다.
  • DBMS는 SELECT 쿼리(조회) 시에는 아무런 잠금을 걸지 않지만 해당 단계에서는 단순 읽기 작업에도 Shared Lock을 걸게 된다.
  • 이렇게 되면 조회가 발생될 때 다른 트랜잭션에서 이 레코드를 변경하지 못하게 된다. 결과적으로 동시 처리 능력이 매우 떨어지게 되고 성능저하가 발생하게 된다.

 

Isolation Level에 따른 문제점 정리

Dirty Read (발생 : Uncommitted read)

  • 동시 트랜잭션이 커밋을 완료하지 않은 변경된 데이터를 조회하여 발생하는 현상

Non Repeatable Read (발생 : Uncommitted read, Committed read)

  • 동시 트랜잭션이 동일한 행을 보고 있을 때 변경 & 커밋을 하게 되면 조회 결과가 달라지는 현상

Phantom Read (발생 : Uncommitted read, Committed read, Repeatable read)

  • 한 트랜잭션 내에서 다른 트랜잭션이 일부 행을 추가/삭제 & 커밋을 하게 되면 조회 때 새로운 행이 생기거나 없어지는 현상

 

트랜잭션 Propagation

트랜잭션 간 전파정도를 설정한다. spring은 Propagation 설정에 따라 트랜잭션의 시작과 일시 중지를 관리한다.

(propagation : 번식)

 

1. REQUIRED (default 값)

  • 부모 Transaction이 존재하면 참여하고, 없으면 새로 만든다.

2. SUPPORTED

  • 부모 Transaction이 존재하면 참여하고, 없으면 Transaction 없이 실행된다.

3. MANDATORY

  • 부모 Transaction이 존재하면 참여하고, 없으면 예외가 발생한다.

4. NEVER

  • 부모 Transaction이 존재하면 예외가 발생하고, 없으면 Transaction 없이 실행된다.

5. NOT SUPPORTED

  • 부모 트랜잭션이 있으면 일시중지하고, 비지니스 로직을 Transaction 없이 실행한다.

6. REQUIRES NEW

  • 부모 트랜잭션이 있으면 일시중지하고, 새로운 Transaction을 생성하여 실행한다.

7. NESTED

  • 부모 트랜잭션이 없다면 새로 만들고, 있다면 중첩 Transaction을 만든다.
  • 중첩 Transaction은 앞선 부모의 commit과 rollback에는 영향을 받지만, 자신의 commit이나 rollback은 부모의 Transaction에 영향을 주지 않는다.

 

REQUIRED_NEW를 사용하여 문제를 해결했던 경우


Reference

https://dev.mysql.com/doc/refman/8.0/en/innodb-transaction-isolation-levels.html#isolevel_repeatable-read  

https://dev.mysql.com/doc/refman/8.0/en/innodb-locking.html

https://suhwan.dev/2019/06/09/transaction-isolation-level-and-lock/

반응형

'Web > 정리글' 카테고리의 다른 글

멀티 쓰레드 정리  (0) 2021.12.20
HTTPS, TLS 정리  (0) 2021.10.19
Exception & Transaction rollback 정리  (0) 2021.09.23
WAS와 웹서버 차이 정리  (0) 2021.09.10
스프링 AOP 정리  (2) 2021.09.08
Comments
반응형
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday