정의
DB 작업을 하나의 단위로 묶어서 처리하는 것
모든 작업이 성공하면 commit, 하나라도 실패하면 rollback
핵심 목적
데이터 일관성 유지
중간 실패 시 전체 작업 취소
동작 흐름
트랜잭션 시작
↓
비즈니스 로직 수행
↓
성공 → commit (DB 반영)
실패 → rollback (전체 취소)
핵심 포인트
commit 시점에 실제 SQL 실행
예외 발생 시 자동 rollback
트랜잭션 안에서만 JPA 기능 동작
정의
엔티티를 관리하는 메모리 공간 (1차 캐시)
특징
1.1차 캐시
같은 엔티티 재조회 시 DB 접근 최소화
2.변경 감지 (Dirty Checking)
user.setName("홍길동");
→ commit 시 자동 UPDATE 실행
3.쓰기 지연
SQL을 모아두었다가 commit 시 실행
| 상태 | 설명 | JPA 관리 | DB 반영 | 예시 |
|---|---|---|---|---|
| 비영속 (Transient) | 아직 DB와 관계 없는 상태 | ❌ | ❌ | new User() |
| 영속 (Managed) | JPA가 관리 중인 상태 | ✅ | ✅ (commit 시) | findById() |
| 준영속 (Detached) | 한 번 관리됐지만 지금은 아님 | ❌ | ❌ | 트랜잭션 종료 후 |
| 삭제 (Removed) | 삭제 예정 상태 | ✅ | ✅ (DELETE) | delete() |
영속 상태일 때만 변경 감지 → 자동 update
❌ 내가생각했던 오해
save = 저장 (insert만 한다)
✔️ 실제
👉 영속 상태로 만드는 메서드
| 상황 | 객체 상태 | save() 동작 | SQL 실행 | 특징 |
|---|---|---|---|---|
| new 객체 | 비영속 (Transient) | 영속 상태로 전환 | INSERT | 새로운 데이터 생성 |
| 조회된 객체 | 영속 (Managed) | 의미 없음 | 자동 UPDATE (Dirty Checking) | save() 필요 없음 |
| ID만 있는 객체 | 준영속 (Detached) | merge 수행 | UPDATE (또는 SELECT 후 UPDATE) | 값 덮어쓰기 위험 |
실무 기준:
save는 생성할 때만 사용
트랜잭션 내부에서 다른 트랜잭션 호출 시 동작 방식
자주사용하는 주요 옵션
REQUIRED (기본) - 기존 트랜잭션 참여
REQUIRES_NEW - 무조건 새 트랜잭션 생성
로그 저장, 감사 기록
→ 실패해도 반드시 남겨야 하는 경우
| 격리 수준 | Dirty Read | Non-repeatable Read | Phantom Read | 특징 |
|---|---|---|---|---|
| READ UNCOMMITTED | ❌ 발생 | ❌ 발생 | ❌ 발생 | 커밋 전 데이터도 읽음 (위험) |
| READ COMMITTED | ✅ 방지 | ❌ 발생 | ❌ 발생 | 커밋된 데이터만 읽음 (기본) |
| REPEATABLE READ | ✅ 방지 | ✅ 방지 | ❌ 발생 | 같은 데이터 유지 |
| SERIALIZABLE | ✅ 방지 | ✅ 방지 | ✅ 방지 | 완전 격리 (성능 낮음) |
| 문제 | 설명 |
|---|---|
| Dirty Read | 커밋 안 된 데이터 읽음 |
| Non-repeatable Read | 같은 조회인데 값이 바뀜 |
| Phantom Read | 조회 결과 개수가 바뀜 |