목차
- 트랜잭션
- ACID
트랜잭션(Transaction)은 DB에서 하나의 작업을 수행하기 위한 논리적인 작업 단위를 의미한다.
예를 들어서, A가 B에게 10만원을 송금하는 작업을 DB에서 처리한다고 가정해보자.
1. A 계좌에서 10만원 출금
2. B 계좌에 10만원 입금
이 두 작업은 반드시 함께 수행되거나 아예 수행되지 않아야 한다.
즉, 여러 작업을 하나로 묶어서, 모든 작업이 성공하면 실행 하나라도 실패하면 이전상태로 되돌리는것, 이 작업 단위를 바로 트랜잭션이라고 한다.
스프링에서의 트랜잭션은 구현이 간단하다.
하나로 묶고싶은 작업 단위를 @Transactional 어노테이션을 사용하여 묶어주기만 하면 된다.
예시코드
@Transactional
public void trade(Long fromId, Long toId, int money){
withdraw(fromId, money); //fromId에서 money를 차감하는 로직 수행
deposit(toId, money); //toId에서 money를 추가하는 로직 수행
}
위 메서드 내부에서 예외가 발생하면 @Transcational 어노테이션에 의해서 Spring이 자동으로 Rollback을 수행하게 된다.
ACID는 데이터베이스 트랜잭션이 반드시 만족해야 하는 네 가지 특성을 의미한다.
ACID의 각 의미는 다음과 같다.
트랜잭션에 포함된 작업은 *모두 성공하거나 모두 실패해야 한다.*
즉, 하나라도 실패하면 `Rollback` 전부 성공하면 `Commit`을 수행한다.
트랜잭션 수행 전후로 데이터베이스의 규칙이 일정해야 한다.
예를들어, A의 계좌에 100만원, B의 계좌에 50만원이 들어있다고 가정하자.
A가 B에게 10만원을 송금한다면 A:90만원 B:60만원 총 금액은 변하지 않는다.
즉, 데이터는 `항상 유효한 상태`를 유지해야 한다.
동시에 여러 트랜잭션이 실행될때, 서로에게 영향을 미치지 않아야한다.
예를 들어, A의 계좌에서 출금하는 중에 다른 사용자가 A에게 입금한다고 가정하자.
이를 잘 처리하지 못한다면 `데이터 충돌`이 발생할 수 있다.
트랜잭션 끼리는 `독립적`으로 실행되어야 한다.
이를 위해 `격리수준`을 사용하게 되는데 격리수준에는
- SERIALIZABLE
- REPEATABLE READ
- READ COMMITTED
- READ UNCOMMITED
등이 있다.
`MYSQL`은 기본적으로 REPEATABLE READ를 기본으로 사용한다.
트랜잭션이 Commit되면 데이터는 영구적으로 보존되어야 한다.
예를들어, 갑자기 게임 서버가 다운된다 하더라도 Commit되어있는 데이터는 복구되어야 한다.
이를 구현하기 위해 데이터베이스는 `로그`나 `디스크 저장`을 활용한다.