트랜잭션(Transaction)이란 데이터베이스에서 논리적인 작업 단위를 묶어서 처리하는 개념이다.
즉, 여러 개의 데이터 변경(SQL 문)이 하나의 트랜잭션 안에서 실행되며, 모든 작업이 성공하면 적용(Commit) 되고, 하나라도 실패하면 전체 취소(Rollback) 되는 방식으로 동작한다.
트랜잭션은 ACID(Atomicity, Consistency, Isolation, Durability) 원칙을 따라야 한다.
START TRANSACTION;
UPDATE accounts SET balance = balance - 1000 WHERE id = 1; -- A 계좌에서 1000원 차감
UPDATE accounts SET balance = balance + 1000 WHERE id = 2; -- B 계좌에 1000원 추가
COMMIT;
ROLLBACK;
트랜잭션의 고립성(Isolation)을 보장하기 위해 격리 수준을 설정할 수 있다.
격리 수준이 높을수록 동시성이 낮아지고, 낮을수록 동시성은 높아지지만 데이터 충돌 가능성이 커진다.
| 격리 수준 | 설명 | 문제 발생 가능성 |
|---|---|---|
| READ UNCOMMITTED | 커밋되지 않은 데이터 읽기 허용 | 더티 리드(Dirty Read) 발생 가능 |
| READ COMMITTED | 커밋된 데이터만 읽기 가능 | 반복 가능하지 않은 읽기(Non-repeatable Read) 발생 가능 |
| REPEATABLE READ | 같은 트랜잭션 내에서 동일한 데이터를 조회하면 항상 같은 결과 반환 | 팬텀 리드(Phantom Read) 발생 가능 |
| SERIALISABLE | 트랜잭션을 순차적으로 실행 (가장 강력하지만 느림) | 모든 문제 해결 가능 |
START TRANSACTION;
UPDATE accounts SET balance = balance - 500 WHERE id = 1;
UPDATE accounts SET balance = balance + 500 WHERE id = 2;
COMMIT;
✅ 모든 쿼리가 성공하면 계좌 이체 완료
❌ 중간에 오류 발생 시 롤백
START TRANSACTION;
UPDATE accounts SET balance = balance - 500 WHERE id = 1;
-- 오류 발생! (예: id = 2 계좌 없음)
UPDATE accounts SET balance = balance + 500 WHERE id = 2;
ROLLBACK;
➡️ 첫 번째 계좌에서 차감된 500원이 원래대로 복구됨
Spring Boot에서는 @Transactional 어노테이션을 사용하여 트랜잭션을 쉽게 관리할 수 있다.
@Service
public class AccountService {
@Autowired
private AccountRepository accountRepository;
@Transactional
public void transferMoney(Long fromAccountId, Long toAccountId, int amount) {
Account fromAccount = accountRepository.findById(fromAccountId).orElseThrow();
Account toAccount = accountRepository.findById(toAccountId).orElseThrow();
fromAccount.withdraw(amount);
toAccount.deposit(amount);
accountRepository.save(fromAccount);
accountRepository.save(toAccount);
}
}
@Transactional이 적용된 메서드는 모든 SQL이 성공해야만 Commit@Transactional 어노테이션으로 쉽게 트랜잭션 적용 가능