Transaction이란❓
하나의 논리적 기능을 수행하기 위한 작업의 단위이다. 즉, 복수 쿼리를 독립적으로 한 단위로 묶는 것이다. 물론, 하나의 쿼리도 transaction으로 볼 수 있다.
여기서 논리적 단위란 한 번에 수행되어야 일련의 연산이다.
그럼 Transaction을 왜 써야 할까❓
데이터의 일관성을 유지하면서, 안정적으로 데이터를 복구하기 위해서 써야된다.
아직 써야되는 이유가 와닿는 거 같지는 않다. Transaction의 특징을 알아보자!!
Transaction 특징
transaction의 특징은 ACID이다.
Atomicity(원자성) -> 단위
- 한 트랜잭션 내에서 실행한 연산들은 하나의 작업으로 본다. 즉, 모두 성공하거나 모두 실패하는 구조를 가진다.
Consistency(일관성) -> 무결성 제약 조건
- 작업 처리 결과는 항상 일관성 있어야된다. DB상태를 일관성 있게 유지해야 한다.
- 트랜잭션 수행 전/후에 데이터 모델의 모든 제약 조건(기본 키, 외래 키, 도메인 제약조건 등)을 만족하는 것을 보장해야 된다.
Isolation(독립성) -> 병행 제어
- 동시에 실행되는 트랜잭션들이 서로에게 영향을 미치지 않아야 한다.
- 어떤 트랜잭션이 다른 트랜잭션에 끼어들 수 없다.(Lock 처리)
Durability(지속성) -> 영속화
- 트랜잭션 작업이 성공하면 결과는 영구적으로 반영되어야 한다.
- 컴퓨터가 종료되거나 시스템 장애가 발생해도 저장되어 영구적으로 반영되어야 함. 즉, RAM이 아닌 SSD에 저장되어야 한다.
😵💫 헷갈리는 용어들 정리하기
일관성: "모든 요소"가 특정 시점에 "균일"한 것이 일관성이다.
정합성: 데이터 정합성. 중복 데이터가 많으면, 데이터의 정합성이 깨질 수 있다.
무결성: 데이터의 값이 정확한 상태
Transaction: 데이터의 정합성을 보장하기 위한 기능
Lock: 동시성을 제어하기 위한 기능
트랜잭션이 데이터의 정합성을 보장해주니까, 막 써도 될까?
아니다! 꼭 필요한 최소의 코드에만 적용하는 것이 좋다. 트랜잭션의 범위를 최소화 하는 것이 좋다.
일반적으로 데이터베이스의 커넥션의 개수가 제한되어 있다. 그런데, 각 단위 프로그램이 커넥션을 소유하는 시간이 길어진다면, 사용 가능한 여유 커넥션의 개수가 줄어든다. 어느 순간에는 각 단위 프로그램에서 커넥션을 가져가기 위해 기다려야 하는 상황이 발생할 수 있다.
여러 트랜잭션을 동시에 실행했을 때, 발생하는 문제점은 없을까?
Dirty Read, Non-repeatable Read, Phantom Read가 발생한다. 앞에서부터 하나씩 알아보자!!
- Dirty Read: 트랜잭션 1이 수정중인(변경만 하고, commit은 하지 않은 상태) 내용을 트랜잭션 2가 read하는 경우에 트랜잭션1이 commit을 하지 않고, rollback을 하면, transaction2는 잘못된 데이터를 읽는 것이다.
- Non-repeatable Read: 트랜잭션 1이 어떤 데이터 A를 2번 조회하는 연산으로 이루어졌다고 가정하자. 트랜잭션 1이 A를 한번 읽은 후, 트랜잭션 2가 A를 수정하고 commit 한다면, 후에 트랜잭션 1이 A를 다시 조회했을 때, 동일한 값을 얻지 못하고, 수정된 A를 얻게 된다.
- Phantom Read: 트랜잭션 1이 어떤 데이터 A를 2번 조회하는 연산으로 이루어졌다고 가정하자. 트랜잭션 1이 A를 조회해서 [1,2,3]의 값을 얻었고, 트랜잭션 2가 A에 [4,5] 값을 추가하고 commit하면, 후에 트랜잭션 1이 A를 다시 조회했을 때, 결과 값이 달라진다.
트랜잭션의 격리 수준
여러 개의 트랜잭션이 동시에 데이터 베이스에 접근했을 때, 해당 트랜잭션들을 어떻게 처리할 것인지에 대한 설정하는 것이다.
격리 수준이 높아질 수록 고립도는 높아지지만, 성능이 떨어진다는 단점이 있다.
먼저 가장 낮은 트랜잭션 격리 수준부터 하나씩 높아지도록 설명하겠다.
- READ UNCOMMITED: commit 되지 않은 데이터도 읽을 수 있도록 허용해준다.
(Dirty Read, Non-repeatable read, phantom read 발생 할 수 있다.)
- READ COMMITED: commit 된 데이터만 읽을 수 있게 허용해준다.
(Non-repeatble read, phantom read가 발생 할 수 있다.)
- REPEATABLE READ: 반복 가능한 읽기. 트랜잭션이 진행되는 동안에는 데이터가 변경되더라도, 같은 데이터를 읽게 해주는 것.
(Phantom read가 발생 할 수 있다.)
- SERIALIZABLE: 직렬화 가능. 가장 강한 격리수준으로 성능은 좋지 못하다. 트랜잭션이 완료될 때까지 select 쿼리가 접근하는 모든 데이터에 shared lock이 걸린다.
내가 자주 쓰는 Mysql에 기본 격리 수준은 REPEATABLE READ이다.
Reference
https://www.youtube.com/watch?v=poyjLx-LOEU