티스토리 뷰
부제: 트랜잭션 격리수준, 트랜잭션 뜻
Transaction. 영한사전에 검색하면 '거래'라는 뜻이다. 전산학(Computer Science)에서 일컫는 트랜잭션(Transaction)은 조금 다르다. 쉽게 풀어쓰자면... 모든 명령어의 성공 또는 실패를 한번에 처리한다는 뜻이다. 조금 더 어렵게 설명하면
데이터베이스의 상태를 바꾸는 기능을 수행하기 위한 작업의 단위
이다. 이 기능이 정상적으로 동작하려면 성공 또는 실패가 한번에 일어나야 한다. 즉, 트랜잭션 처리가 잘 끝나야 한다. 지금부터 트랜잭션 처리가 왜 필요한지 알아보자.
1. 트랜잭션 처리가 필요한 이유.
가장 많이 쓰이는 예제. 계좌 이체를 예로 들어보겠다. 철수가 영희에게 1000원을 송금하는 상황은 아래와 같이 요약할 수 있다.
철수의 계좌에서 1000원 출금
영희의 계좌에 1000원 입금
그런데 만약 철수의 계좌에서 출금이 성공했지만, 영희의 계좌에 입금하는 도중 오류가 발생한다면? 철수의 계좌에서는 이미 천원이 줄었으나, 영희는 받은 돈이 없는 상황이 발생한다.
당연히 이러한 상황은 절대 발생하면 안된다. 그래서 이 두가지 기능(철수 계좌에서 출금, 영희 계좌에 입금)을 하나의 트랜잭션으로 관리해야 한다. 하나의 트랜잭션으로 관리하면, 영희의 계좌에 입금하는 기능이 실패했을 경우, 철수의 계좌에 돈이 다시 입금되어야 한다. (이를 Rollback 이라고 한다.)
2. 트랜잭션의 성질
위에서 설명했던 예제를 토대로 트랜잭션의 성질에 대해 알아보자.
원자성(Atomicity): 한 트랜잭션 내에서 실행한 작업들은 하나로 간주한다. 즉, 모두 성공 또는 모두 실패.
일관성(Consistency): 트랜잭션은 일관성 있는 데이타베이스 상태를 유지한다. (data integrity 만족 등.)
격리성(Isolation): 동시에 실행되는 트랜잭션들이 서로 영향을 미치지 않도록 격리해야한다.
지속성(Durability): 트랜잭션을 성공적으로 마치면 결과가 항상 저장되어야 한다.
3. 여러개의 트랜잭션이 경쟁한다면
그냥 한번에 일어나야 하는 작업들을 하나의 동작처럼 묶어주면 끝이라고 생각할 수 있다. 하지만 '여러개의' 트랜잭션이 동시에 실행되는 상황을 고려해야 한다. 특정 트랜잭션이 수정 후 아직 커밋하지 않았는데 다른 트랜잭션이 그 레코드에 접근할 수도 있다.
이러한 경쟁 상황에 발생할 수 있는 문제는 크게 3가지이다. 그리고 이를 해결하기 위한 트랜잭션 격리 수준(Transaction Isolation Level)이 정의되어 있다. 먼저 문제 3가지에 대해 다뤄보려고 한다.
Problem1 - Dirty Read
트랜잭션 A가 어떤 값을 1에서 2로 변경했다. 아직 커밋하지 않은 상황에서, 트랜잭션B가 같은 값을 읽는다면? 트랜잭션 B는 2를 읽을 것이다. 이 때 A가 롤백된다면? 트랜잭션B는 잘못된 값을 읽은 것이 된다.
요약하면, 아직 수정 중인 데이터에 접근을 허용할 경우 발생하는 데이터 불일치이다.
Problem2 - Non-Repeatable Read
트랜잭션 A가 값 1을 읽었다. 이후 A는 같은 쿼리를 또 실행할 예정인데, 그 사이에 트랜잭션 B가 값 1을 2로 바꾸고 커밋하면? A는 같은 쿼리 두번을 날렸으나, 두 쿼리의 결과가 다르게 된다.
요약하면, 한 트랜잭션에서 같은 쿼리를 두번 실행했을 때 발생하는 데이터 불일치이다. 앞서 설명한 Dirty Read에 비해서는 발생 확률이 좀 적다. (한 트랜잭션에서 같은 쿼리를 두번 실행해야 하니까)
Problem3 - Phantom Read
트랜잭션 A가 어떤 조건을 사용하여 특정 범위의 값들 [0,2,4,6,8]을 읽었다. 이후 A는 같은 쿼리를 실행할 예정인데, 그 사이에 트랜잭션 B가 같은 테이블에 값[1,3,5]을 추가하고 커밋했다면? A는 같은 쿼리를 다시 실행했지만 두번째 결과는 [1,2,3,4,5,6,8]을 얻는다.
요약하면, 한 트랜잭션에서 일정 범위의 레코드를 두번 이상 읽을 때 발생하는 데이터 불일치이다. 앞서 설명한 문제점들 보다 발생 확률이 가장 적다.
4. 트랜잭션 격리수준
이와 같은 문제와 연관된 트랜잭션 격리 수준은 총 4가지이다. 수준(Level)이 높을수록 성능은 떨어지므로, 높은 격리 수준을 채택하는 것이 항상 좋은 방법은 아니다. 적절한 수준을 채택하는 것이 좋다.
Level0 - Read Uncommited
다른 트랜잭션이 커밋하지 않은 레코드에 접근이 가능하다. 가장 낮은 수준의 트랜잭션 격리이다. 그래서 앞서 언급한 3가지 문제가 모두 발생한다. 그러나 성능은 가장 뛰어나다.
Level1 - Read Commited
항상 커밋된 레코드만 읽는다. 그러므로 아직 커밋되지 않는 레코드를 읽다가 발생하는 Dirty Read는 방지된다. 하지만 나머지 두가지 문제는 예방할 수 없다. 대부분의 DBMS에서 기본적으로 채택하고 있는 방식으로 알려져 있다.
Level2 - Repeatable Read
특정 트랜잭션이 읽은 레코드에 대하여 그 트랜잭션이 끝날 때까지 다른 트랜잭션이 수정/삭제하는 것을 방지한다. 한 트랜잭션에서 같은 쿼리를 두번 실행했을 때 결과가 다른 문제인 Non-Repeatable-Read가 예방된다. 하지만 특정 범위를 지정한 것도 아니고, 레코드 생성을 방지한 것은 아니므로 Phantom Read는 예방할 수 없다. MYSQL에서 채택하고 있는 방식이다. (다만, mysql의 Repeatable Read는 Phantom Read를 방지한다.)
Level3 - Serializable Read
어떤 트랜잭션이 여러개의 레코드를 조회할 때, 그 트랜잭션이 끝날 때까지 조회 범위에 새로운 레코드를 조회/생성/수정/삭제 하는 것을 방지한다. 모든 동시성 관련 문제를 예방할 수 있으나, 성능이 가장 안좋다.
트랜잭션 격리 수준과 이에 따른 문제 발생에 관련된 내용을 표로 정리해봤다.
Problems Isolation Level | Dirty Read | Non-Repeatable Read | Phantom Read |
Read Uncommitted | 발생 | 발생 | 발생 |
Read Committed | - | 발생 | 발생 |
Repeatable Read | - | - | 발생 |
Serializable Read | - | - | - |
-끝-
출처 및 참고
http://wiki.gurubee.net/pages/viewpage.action?pageId=3900389
https://stackoverflow.com/questions/11043712/what-is-the-difference-between-non-repeatable-read-and-phantom-read
'IT > 기술면접' 카테고리의 다른 글
[JAVA] Interface vs Abstract Class (0) | 2020.07.05 |
---|---|
JAVA의 Garbage Collection을 소개합니다 (0) | 2018.03.07 |
JAVA의 Exception(예외)이란 무엇인가 (0) | 2018.02.02 |
싱글턴(Singleton)패턴에 대해 자세히 알아보자 (1) | 2018.01.07 |
[JAVA] String, StringBuilder, StringBuffer에 대하여 (0) | 2017.10.05 |