트랜잭션이란?
트랜잭션은 데이터베이스에서 수행되는 작업 단위를 의미합니다.
여러 개의 데이터베이스 연산(INSERT, UPDATE, DELETE 등)을 하나의 논리적인 작업 단위로 묶어서 실행하는 것입니다.
이 때, 모든 연산이 성공적으로 수행되면 트랜잭션을 커밋(commit)하여 데이터베이스에 반영하고, 하나라도 실패하면 롤백(rollback)하여 이전 상태로 되돌립니다.
트랜잭션의 목적은 데이터베이스 서버에 여러 개의 클라이언트가 동시에 액세스 하거나 응용프로그램이 갱신을 처리하는 과정에서 중단될 수 있는 경우 등 데이터 부정합을 방지하고자 할 때, 쉽게 말하면 여러 작업을 묶을 때 사용한다.
잠금(Lock) vs 트랜잭션(Transaction)
트랜잭션은 작업의 완전성을 보장해주는 것이다. 즉 논리적인 작업 셋을 모두 완벽하게 처리하거나, 처리하지 못할 경우에는 원 상태로 복구해서 작업의 일부만 적용되는 현상이 발생하지 않게 만들어주는 기능이다.
잠금은 트랜잭션은 서로 비슷한 개념 같지만 사실 잠금은 동시성을 제어하기 위한 기능이고 트랜잭션은 데이터의 정합성을 보장하기 위한 기능이다.
트랜잭션의 성질 (ACID)
- Atomicity (원자성)
- 하나의 트랜잭션이 더 이상 작게 쪼갤 수 없는 최소한의 업무 단위이다.
- 트랜잭션의 연산은 데이터베이스에 모두 반영되든지 아니면 전혀 반영되지 않아야 한다.
- Consistency (일관성)
- 트랜잭션이 그 실행을 성공적으로 완료하면 언제나 일관성 있는 데이터베이스 상태로 변환한다.
- 시스템이 가지고 있는 고정요소는 트랜잭션 수행 전과 트랜잭션 수행 완료 후의 상태가 같아야 한다.
- Isolation (독립성)
- 둘 이상의 트랜잭션이 동시에 병행 실행되는 경우 어느 하나의 트랜잭션 실행 중에 다른 트랜잭션의 연산이 끼어들 수 없다.
- 수행중인 트랜잭션은 완전히 완료될 떄까지 다른 트랜잭션에서 수행 결과를 참조할 수 없다.
- Durability (영속성)
- 성공적으로 완료된 트랜잭션의 결과는 시스템이 고장나더라도 영구적으로 반영되어야 한다.
트랜잭션 주의사항 - 트랜잭션을 최소화
트랜잭션에는 필요한 최소의 코드에만 적용하는 것이 좋음
- 데이터베이스 커넥션은 개수가 제한적이어서 각 단위 프로그램이 커넥션을 소유하는 시간이 길어질 수록 사용 가능한 여유 커넥션의 개수는 줄어들 것이고 어느 순간에는 각 단위 프로그램에서 커넥션을 가져가기 위해 기다려야 하는 상황이 발생할 수도 있음
- 메일 전송이나 FTP 파일 전송 작업 또는 네트워크를 통해 원격 서버와 통신하는 등과 같은 작업은 어떻게 해서든 DBMS 트랜잭션 내에서 제거하는 것이 좋다. 프로그램이 실행되는 동안 메일 서버와 통신할 수 없는 상황이 발생한다면 웹 서버 뿐 아니라 DBMS 서버까지 위험해지는 상황이 발생할 것
@Transactional
과 JPA
- 트랜잭션 범위 내의 1차 캐시
- 1차 캐시는 영속성 컨텍스트 내부에 존재하는 캐시로, 엔티티를 조회하면 그 결과를 저장
- 이후 같은 엔티티를 조회하면 캐시에서 먼저 조회하게 되므로 데이터베이스를 접근하지 않고도 빠르게 가져올 수 있음
- 트랜잭션 범위 내의 Dirty Checking
- 매번 영속성 컨텍스트를 확인하여 변경 사항이 있는지 감지하고 엔티티의 개수만큼 UPDATE 쿼리가 실행되므로, 엔티티 개수가 많은 경우에는 많은 오버헤드가 발생할 수 있음
@Transactional(readOnly=true)
- 트랜잭션을 읽기 전용으로 수행
- 스프링 프레임워크가 하이버네이트 세션 플러시 모드를 MANUAL로 설정하기 때문에 강제로 플러시를 호출하지 않은 한 플러시가 일어나지 않아, CUD 작업이 동작하지 않음
- 영속성 컨텍스트는 변경감지를 위한 스냅샷을 보관하지 않으므로 성능 향상
- 트랜잭션 하위 시스템에 대한 힌트 역할을 수행
- write 연산을 실행했을 때 오류가 나는 것은 아님
- DB가 master와 slave로 나누어져 있는 경우 readOnly 를 통해 slave 를 호출할 수 있음
- Spring Data JPA 에서 제공하는 JpaRepository 의 기본 구현체는 SimpleJpaRepository 인데 이미 최상단에 @Transactional(readOnly) 가 붙어있음
- 읽기 메서드들은 이미 readOnly 형태로 제공
- 읽기 전용 힌트를 해설할 수 없는 트랜잭션 매니저는 exception을 던지지는 않고 hint를 무시한다.
- DB 마다 읽기 전용 트랜잭션에 대한 동작 방식이 다름
- https://lob-dev.tistory.com/entry/DBMS-별-Transaction-Read-Only에-대한-동작-방식-1
참고