Spring DB : DB 트랜잭션의 이해 (1)

    이 글은 인프런 김영한님의 강의를 복습하며 작성한 글입니다.

     

    DB 트랜잭션 동작방식 확인

    이 게시글에서는 DB 트랜잭션 동작방식을 그림으로 이해를 해보려고 한다. 아래에 관련 내용을 정리했다. 

     

    트랜잭션 사용법

    • 데이터 변경 쿼리를 실행했다. 쿼리를 실행한 것은 DB에 변경 결과를 실제로 반영하는 상태는 아니다.
    • DB에 실제 데이터 변경을 반영하기 위해서는 Commit 명령어를 호출해야한다.
    • 실행된 쿼리를 반영하고 싶지 않으면 RollBack 명령어를 호출한다. 
    • Commit을 호출하기 전까지 변경된 데이터는 임시로 저장되는 것이다. 따라서 해당 쿼리를 실행한 사용자에게는 변경 정보가 보이지만, 다른 사용자에게는 보이지 않는다. 

    위의 내용에서 가장 중요하게 여겨봐야 할 부분은 내 입장에서는 적어도 두 가지다. 

    1. 변경 쿼리는 실제 DB 테이블에 변경값이 임시 상태로 저장된다.
    2. 임시 상태로 저장된 값은 쿼리를 실행한 세션(사용자)만 확인할 수 있다. 다른 사용자에게는 변경되지 않은 값이 보인다. 

     

     

    그림으로 이해하기

    초기 상태

    현재 상태는 각 사용자가 DB와 각각 커넥션을 맺어둔 상태다. 이 때, 각 세션이 DB 테이블을 조회하면 동일한 테이블만 확인된다. 즉, 기존 회원 데이터만 보이게 되는 상황이다.

    세션 1, 삽입 쿼리

    이 때, 세션1이 삽입 쿼리를 실행했다. 그 결과로 DB 테이블에는 신규 회원1, 신규회원 2가 들어간다. 그런데 이 때 커밋을 하지 않았기 때문에 테이블에 신규 회원1, 신규 회원2의 상태는 '임시'로 저장이 된다. 

    이 상태일 때, 세션1이 커밋을 하지 않고 DB를 조회하면 '임시'인 녀석들도 다 조회가 가능하다. 그렇지만 다른 세션이 DB를 조회하면, 커밋된 것만 보이기 때문에 '완료' 상태인 기존 회원만 확인할 수 있다. 

    세션1 : 커밋

    이 때, 세션1이 커밋을 한다. 커밋 시, 세션 1에 의해 삽입되어 DB 테이블에 '임시' 상태로 있던 데이터들의 상태가 모두 '완료'로 변경된다. 이 때 세션1과 세션2가 DB를 각각 조회하면, 두 세션 모두 신규회원 1 / 신규회원 2의 값을 확인할 수 있게 된다. 정리하면 세션1이 커밋하면, 변경된 데이터가 DB에 즉시 반영이 된다. 

     

     

    커밋되지 않은 데이터를 읽을 순 없을까?

    세션 1 삽입 후, 커밋전

    세션 1이 삽입 후 커밋을 하기 전의 상태다. 이 때, 세션 2는 DB를 조회했을 때, 세션 1이 삽입한 데이터를 읽어오지 못한다고 했다. 사실 읽어오게 하는 방법은 있다. 트랜잭션 격리 수준을 "READ UNCOMMITTED"로 입력하면 그렇게 할 수 있다. 그런데 왜 굳이 기본적으로 커밋된 데이터만 읽어오게 하는 것일까? 

    세션2가 커밋 전, 신규회원들을 읽어온다면?

    위의 그림을 한번 살펴보자. 세션 1이 커밋하기 전, 세션 2가 커밋되지 않은 신규회원 1 / 신규회원 2 데이터를 읽을 수 있다고 가정해보자. 

    세션2 데이터

    그렇게 가정할 경우, 세션2는 DB를 조회했을 때 다음과 같은 데이터를 얻을 수 있게 될 것이다. 이 때, 세션1이 불의의 사건으로 인해 롤백을 한다고 해보자. 그러면 세션1이 DB에 넣어서 '임시' 상태로 있던 신규회원1, 신규회원2의 데이터는 DB에서 모두 삭제가 되게 된다. 

    롤백 후 세션2 / DB 데이터

    세션1가 불의의 사건으로 롤백하면 DB에는 다음과 같이 기존 회원 데이터만 남아있다. 그렇지만 세션2의 데이터까지 세션1이 롤백해주지는 않는다. 따라서 세션2는 여전히 롤백 전에 DB에서 읽어왔던 '신규 회원1, 신규 회원2' 데이터를 가지고 있다. 만약 세션 2가 이것을 바탕으로 비즈니스 로직을 하고 DB에 밀어넣기라도 하면 데이터 정합성에 큰 문제점이 발생할 수 밖에 없다. 

    이런 이유 때문에 기본적으로 DB는 'READ COMMITTED'의 트랜잭션 격리 수준을 설정해준다. 

     

    정리

    • 세션이 쿼리를 실행하면, 쿼리를 실행한 데이터는 DB에 '임시'상태로 저장된다. 
    • 임시 상태로 저장된 데이터는 해당 쿼리를 실행한 세션만 조회가 가능하다. 다른 세션은 해당 값을 조회할 수 없다.
    • 다른 세션이 '임시 상태'인 DB의 값을 확인할 수 없는 이유는 트랜잭션 격리 수준을 'READ COMMITTED'로 해두었기 때문이다.
    • 커밋되지 않은 값을 읽을 경우, 데이터 정합성에 큰 문제가 발생할 수 있다. 

    댓글

    Designed by JB FACTORY