트랜잭션 (Transaction)
what: 데이터베이스의 상태를 변환시키는 작업 단위를 이야기 한다.
트랜잭션이 왜 필요한가
관련있는 작업의 단위를 묶어서, 한번에 처리하거나 문제가 발생한경우 롤백을 용이하게 하기 위해서 사용한다.
- 만약 두개의 테이블이 있다고 가정하자.
- 주문번호, 날짜, 고객번호를 가진
테이블 A
- 주문번호, 상품코드, 주문한 상품개수를 가진
테이블 B
- 주문번호, 날짜, 고객번호를 가진
- 주문이 발생했다고 생각하자.
- 주문번호가 생성되고, 현재 시간과, 주문한 고객정보가
테이블 A
에 추가가 될것이다. - 이때
테이블 B
의 정보도 같이 추가되어야 한다. - 만약 고객이 여러종류, 여러개의 상품을 구매했다면
테이블 B
에는 여러 행이 추가 될것이다.
- 주문번호가 생성되고, 현재 시간과, 주문한 고객정보가
- 에러가 발생했다.
테이블 B
의 4번째 행을 추가할때 에러가 발생했다고 하자.- 주문 자체가 취소되어야 하여, 1,2,3 번째의 행을 삭제해주어야 한다.
- 이것을 일일히 다 삭제하고 하려면 굉장히 번거롭고 귀찮은 작업이다.
이런 작업들을 한번에 묶어서 처리할수 없을까??
- 트랜잭션 을 이용한다.
트랜잭션의 임시공간
트랜잭션은 여러개의 SQL 명령을 한개의 작업으로 묶을 수 있다.
- 이때 SQL 명령의 결과들은 임시공간에 저장되고 있고,
COMMIT
을 하게 되면 실제 테이블에 적용이 된다. COMMIT
: 트랜잭션을 통해 변경된 사항을 적용하는 명령ROLLBACK
: 변경된 사항을 적용하지 않고 종료하는 명령- 위의 주문에러 예시의 경우,
ROLLBACK
을 하면 깔끔하게 처리가 된다.
- 위의 주문에러 예시의 경우,
트랜잭션 고립화 레벨 (Isolation Level)
what: 트랜잭션 실행중 다른 연산이 접근 불가능하게 하여, 고립하는 수준
트랜잭션 고립화 레벨을 왜 알아야하는가 (WHY)
트랜잭션에서 일관성이 없는 데이터를 허용도록 하는 수준을 알고 있어야, 데이터 베이스 관리가 용이해진다.
- 데이터베이스는 무결성을 중요하는것이 무엇보다 중요하다.
- 트랜잭션은 여러개의
SQL
명령을 처리 하는데, 이때 중간에 다른 트랜잭션이나 SQL 명령으로 인해 데이터 베이스내 데이터에 영항을 준다면 일관성과 무결성이 무너질 수 있다. - 이것을 방지하기 위해 한 트랜잭션이 처리중일때, 다른 트랜잭션은 DB에 접근하지 못하게 하는
Locking
이라는 방법을 쓴다.- 하지만 과도한
Locking
은 성능을 떨어뜨리게 된다.
- 하지만 과도한
- 이런
Locking
을 효율적으로 사용하는 방법을 분류한것이Iolation Level
이다.
Isolation Level의 종류
Read Uncommited
트랜잭션에서의 변경내용이 COMMIT되기전, 다른 트랜잭션에서 값을 읽을 수 읽을 수 있다.
- 트랜잭션 처리된 작업의 중간 결과를 볼 수 있다.
발생할 수 있는 문제점
(DirtyRead)
- 한 트랜잭션이 A를 B로 변경하고 있을때
- 다른 트랜잭션이 A의 위치를 읽게 되면
- A가 아닌 B라는 결과를 얻을 수 있다.
(DirtyRead)
- 이때
Uncommited
라는 단어처럼 아직 완료되지 않은 작업에 대한 접근이 가능해지는것이다.
Read Commited
커밋된 데이터만 읽는다.
- 한 트랜잭션이 A를 B로 변경하고 있을때
- 다른 트랙잭션은 변경되고 있는 A의 위치를 읽을 수 없다,
- 대신 스냅샷을 이용해 백업되어있는 값A 을 가져오게 된다.
- 하지만 A를 B로 변경하는데 성공하고 Commit을 했다면, 이제는 다른 스냅샷에 B가 있으므로 B값을 가져오게된다.
(Non-Repetable Read)
발생할 수 있는 문제점:
(Non-Repetable Read)
- 한 트랜잭션에서 같은 쿼리를 두번 실행했을때, 수정된 데이터를 다르게 읽기 때문에 다른결과가 나올 수 있다.
Repeatable Read
하나의 트랜잭션에서는 본인이 수정하지 않은 데이터에 대해서는 같은 결과를 보장한다.
- 트랜잭션이 완료될때까지 사용하는 데이터에는
Locking
이 걸리게 된다. - 하지만 범위 자체에 대한
Locking
은 걸리지 않는다. - 또한 트랜잭션이 직접적으로 변경하거나 접근하고 있는 데이터를 제외한 다른 데이터에는 접근이 가능하다. (Update)
- 삽입도 가능하다 (Insert)
-
MYSQL
에서 기본적으로 제공하는 격리 레벨이다. col
라는 열의 데이터에는{A B C D}
가 있고- 트랜잭션1이
col
의 데이터중A
와C
에 수정하고 있다면 -
트랜잭션2는 나머지인
B
와D
에 접근할 수 있다. - 트랜잭션에서
A
라는 데이터에 접근했다면, 실제로는A
라는 데이터가 변경되었어도 한 트랜잭션 내에서는 계속해서A
라는 일관된 값을 얻어올 수 있다. - 이것이 가능한 원리는, MYSQL 기준 트랜잭션 id는 실행순서에 따라 오름차순으로 저장되어있는데 항상 자기보다 낮은 트랜잭션id보다 작은것에서 변경한것만 읽기 때문이다.
- 만약 실제 데이터가 자기보다 높은 트랜잭션id가 적혀있다면, Undo영역의 데이터를 가져오게 된다.
- 트랜잭션1: A읽음 (1001번 트랜잭션
begin()
) - 트랜잭션2: A를 B로 변경시작 (1002번 트랜잭션
begin()
) - 트랜잭션2: A를 B로 변경완료 (1002번 트랜잭션
end()
) - 트랜잭션1: A읽음 (B로 변경한 1002번 트랙잭션 결과 무시
1002 > 1001
, Undo 영역의 A를 읽음)
- 트랜잭션1: A읽음 (1001번 트랜잭션
발생할 수 있는 문제점:
(Phantom Read)
- 삽입하지 않은놈이 갑자기 보이거나, 삭제하지도 않았는데 있던놈이 사라지는 경우가 발생 할 수 있다.
- 이 문제는 자신이 타켓 자료를 변경하지 않는 이상, 처음 조회한 그 형상 그대로를 유지한다는 특징때문에 발생한다.
- 만약 다른 트랜잭션에서 그 자료를 조작하고 커밋을 했다고 하더라도 말이다.
id | value |
---|---|
1 | A |
2 | B |
3 | C |
4 | D |
col
라는 열의 데이터에는{A B C D}
가 있다고 가정해보자- 1번 트랜잭션이 먼저 데이터
E
를 넣고, 아직 커밋을 하지 않았다고 해보자. - 이후 시작된 2번 트랜잭션에서 전체 데이터을 읽으면,
{A B C D}
가 보이게된다. - 그리고 2번 트랜잭션이
F
라는 데이터를 삽입한다고 해보자. - 1번 트랜잭션이 변경을 완료한뒤 커밋을 한다.
- 2번 트랜잭션이
F
삽입 작업을 마친뒤 전체 데이터를 읽으면 아래와 같은 결과를 얻게된다.
id | value |
---|---|
1 | A |
2 | B |
3 | C |
4 | D |
5 | E |
6 | F |
- 범위에 대한 락이 걸리지 않았기때문에, 이전에 없었던
E
가 보인다. - 한 트랜잭션 내에서 삽입하지 않은놈이 갑자기 보이는 현상 이다.
(Phantom Read)
삭제 예시
id | value |
---|---|
1 | A |
2 | B |
- 2번 트랜잭션이 끝나기전, 2번 보다 늦게 시작한 3번 트랜잭션에서
1번 id
를 가진 데이터A
를 삭제하고 커밋까지 완료했다고 해보자.
id | value |
---|---|
2 | B |
커밋까지 완료된 실제 데이터(3번 트랜잭션에서의 작업내용)
id | value |
---|---|
1 | A |
2 | B |
2번 트랜젝션에서 보이는 잘못된 데이터
- 2번 트랜잭션에서
1번 id
에 대한 데이터는 보이지만, 업데이트를 하는 경우 실패하는 현상이 일어날 수 있다. (눈에는 보이지만, 실제로는 없어진 현상) - 왜냐하면 이전의 스냅샷만 계속 보기 때문에 처음 조회한 그 형상 그대로를 계속 보게 되기 때문이다.
Serializable
Repeatable Read
에서의 부분 접근조차 막아버린다.- 직렬성 위반이 발생하지 않는다.
- ACID중 Consistency(일관성) 를 완전히 지킬 수 있게된다.
- 하지만, 성능이 사용하기 힘들정도록 낮아지게 되기때문에 잘 사용하지 않는 레벨이다.
Conclustion
- 트랜잭션을 이용해, 데이터 베이스 상태를 변경시키는 여러개의 쿼리를 한개의 작업으로 묶을 수 있다.
- 트랜잭션 격리 레벨을 통해, 데이터베이스내의 데이터 일관성을 보장하는 정도를 정할 수 있다.
- 격리 레벨의 정도에 따라서, 발생할 수 있는 데이터 일관성 위반의 경우의 수가 다르다.
Isolation Level \ Non Consistency | Dirty Read | Non-Repeatable Read | Phantom Read |
---|---|---|---|
Read Uncommited | o | o | o |
Read commited | x | o | o |
Repeatable Read | x | x | o |
Serializable | x | x | x |
Reference
- https://en.wikipedia.org/wiki/Isolation_(database_systems)#Phantom_reads
- https://goodgid.github.io/Transaction-Isolation-Level/
- https://mysqldba.tistory.com/334
- https://nesoy.github.io/articles/2019-05/Database-Transaction-isolation
- https://www.postgresql.kr/blog/pg_phantom_read.html
- https://www.youtube.com/watch?v=e9PC0sroCzc&t=416s&ab_channel=%EC%9A%B0%EC%95%84%ED%95%9CTech
- https://robin00q.tistory.com/19
- https://needjarvis.tistory.com/161