6주차 Unit 6.1 — 트랜잭션이란

Psj·2026년 6월 1일

F-lab

목록 보기
202/239

Unit 6.1 — 트랜잭션이란

F-LAB JAVA · 6주차 · Phase 6 · 트랜잭션과 ACID
💎 Phase 6 시작 — 트랜잭션 ACID, 면접 단골 5개 ★깊이 집중


📌 학습 목표

이 Unit을 끝내면 다음을 답할 수 있어야 한다.

  • 트랜잭션의 정의 ("한 단위의 작업") 는?
  • 계좌 이체 예시 의 트랜잭션 단위는?
  • Commit 의 의미는?
  • Rollback 의 의미는?
  • 트랜잭션의 끝 두 가지는?
  • 게시글 작성 시 트랜잭션 단위는?
  • "단위" 의 크기 결정 기준은?
  • JDBC autocommit 과의 관계는?
  • Spring @Transactional 은?

🎯 핵심 한 문장

트랜잭션은 여러 작업을 한 단위로 묶어 모두 성공해서 영구 적용 (Commit) 되거나 모두 취소 (Rollback) 되도록 하는 단위로, 계좌 이체에서 "A 출금 + B 입금" 을 하나의 트랜잭션으로 묶어야 둘 중 하나만 일어나는 사고를 막을 수 있다.
트랜잭션 (Transaction) 은 한 단위의 작업으로 취급되는 모든 작업을 묶은 것이다.
대표 예시인 계좌 이체 는 (1) A 계좌에서 출금, (2) B 계좌에 입금 — 두 작업을 하나의 단위로 묶음 이 트랜잭션이다.
트랜잭션의 끝은 두 가지 — Commit (모든 변경을 영구 적용) 또는 Rollback (모든 변경을 취소) 으로, 중간 상태는 절대 외부에 노출되지 않는다.
"단위" 의 크기는 비즈니스 의미에 따라 정한다 — 게시글 작성 시 "게시글 INSERT + 첨부파일 INSERT + 알림 INSERT" 를 하나로 볼지 분리할지는 도메인 요구사항이 결정하며, 너무 길면 락 점유로 동시성 ↓, 너무 짧으면 일관성 위험이라 균형이 필요하다.

비유 — ATM 이체 거래

트랜잭션 = ATM 이체:

이체 작업 (한 단위):
  1. A 계좌 출금 (-10만)
  2. B 계좌 입금 (+10만)
  → 둘 다 성공 or 둘 다 실패

성공 (Commit):
  - "이체 완료" 인쇄
  - 영구 기록
  - 누구도 못 되돌림

실패 (Rollback):
  - "이체 실패" 인쇄
  - A 계좌도 그대로 (출금 취소)
  - 둘 다 처음 상태

중간 상태 (X):
  - "A 만 출금" 상태 외부에 X
  - 트랜잭션 진행 중엔 안 보임

단위 크기:
  - "이체" = 출금 + 입금 (2개)
  - 너무 크면: "한 달 거래" → 락 길게
  - 너무 작으면: "출금" 만 → 일관성 깨짐

JDBC autocommit:
  - 자동 commit (각 SQL = 1 트랜잭션)
  - 의도적 묶으려면 false

→ 트랜잭션 = 한 단위 작업, Commit/Rollback 으로 끝, 단위는 비즈니스로 결정.


🧭 9개 섹션 로드맵

1. 트랜잭션 정의
2. 계좌 이체 예시
3. Commit
4. Rollback
5. 트랜잭션의 끝
6. 게시글 작성 단위
7. "단위" 의 크기
8. JDBC autocommit
9. Spring @Transactional

1️⃣ 트랜잭션 정의

1.1 정의

트랜잭션 (Transaction):

  "한 단위의 작업" 으로
  취급되는 모든 작업.

  - 여러 SQL 을 묶음
  - 전부 또는 전무

1.2 키워드

키워드:

  - 단위 (Unit)
  - 묶음 (Group)
  - 전부 / 전무 (All or Nothing)
  - 원자성 (Atomicity, Phase 6.2)

1.3 ACID

ACID (트랜잭션 4성질):

  A - Atomicity (원자성)
  C - Consistency (일관성)
  I - Isolation (격리성)
  D - Durability (지속성)

→ Phase 6.2~6.5 각각 ★깊이

1.4 ILIC 의 맥락

트랜잭션 (ILIC)

ILIC 사례:
  - 배송 예약 생성:
    1. 예약 INSERT
    2. 배송 INSERT (예약 참조)
    3. 운임 계산 INSERT
    → 한 트랜잭션

  - 모두 성공 or 모두 실패
  - 중간 실패 시 전체 취소
  - 데이터 일관성

→ ILIC 의 핵심

1.5 자기 점검 답변

트랜잭션의 정의는?

:
1. 정의:

  • 한 단위 작업
  1. 묶음:

    • 여러 SQL
  2. All or Nothing:

    • 전부/전무
  3. ACID:

    • 4성질

2️⃣ 계좌 이체 예시

2.1 시나리오

계좌 이체:

  A → B 10만원 이체

  작업:
    1. A 출금 -10만
    2. B 입금 +10만

  → 한 트랜잭션

2.2 트랜잭션 없으면

트랜잭션 없으면:

  1. A 출금 ✅
  2. B 입금 ❌ (장애)

  → A 만 10만 사라짐
  → 누구도 받지 못한 돈
  → 사고

2.3 트랜잭션 있으면

트랜잭션 있으면:

  1. A 출금 ✅
  2. B 입금 ❌ (장애)
  
  → 자동 Rollback
  → A 도 원상복구
  → 둘 다 처음 상태
  → 안전

2.4 SQL

-- 계좌 이체 트랜잭션
BEGIN;                                       -- 시작
UPDATE accounts SET balance = balance - 100000 WHERE id = 'A';
-- 만약 여기서 장애 → 자동 rollback
UPDATE accounts SET balance = balance + 100000 WHERE id = 'B';
COMMIT;                                       -- 끝 (성공)

-- 또는
ROLLBACK;                                     -- 끝 (실패, 취소)

2.5 ILIC 의 맥락

// 계좌 이체 같은 트랜잭션 (ILIC)
@Service
public class ShipmentBookingService {
    
    @Transactional   // 트랜잭션 시작
    public void createBookingWithShipment(Booking b, Shipment s) {
        // 1. 예약 저장
        bookingDao.add(b);
        
        // 2. 배송 저장 (예약 참조)
        s.setBookingId(b.getId());
        shipmentDao.add(s);
        
        // 3. 운임 계산 저장
        BigDecimal freight = freightCalculator.calculate(s);
        freightDao.save(s.getId(), freight);
        
        // 모두 성공 → commit
        // 하나라도 실패 → 전체 rollback
    }
    
    BookingDao bookingDao;
    ShipmentDao shipmentDao;
    FreightCalculator freightCalculator;
    FreightDao freightDao;
}
class Booking { Long getId() { return null; } }
class Shipment { Long getId() { return null; } void setBookingId(Long id) {} }
class BookingDao { void add(Booking b) {} }
class ShipmentDao { void add(Shipment s) {} }
class FreightDao { void save(Long id, java.math.BigDecimal f) {} }
class FreightCalculator { java.math.BigDecimal calculate(Shipment s) { return null; } }

2.6 자기 점검 답변

계좌 이체 예시의 트랜잭션 단위는?

:
1. 시나리오:

  • A 출금 + B 입금
  1. 없으면:

    • 사고 (한쪽만)
  2. 있으면:

    • 자동 rollback
  3. SQL:

    • BEGIN/COMMIT/ROLLBACK

3️⃣ Commit

3.1 Commit

Commit:

  트랜잭션 성공:
    - 모든 변경 영구 적용
    - 다른 세션도 봄 (격리 후)
    - 되돌릴 수 없음

3.2 의미

의미:

  "확정":
    - "이대로 가자"
    - 변경 보존
    - 트랜잭션 종료

3.3 동작

Commit 동작:

  1. 모든 변경 디스크 반영
  2. 트랜잭션 로그 (WAL)
  3. 락 해제
  4. 트랜잭션 종료
  5. 세션은 다음 트랜잭션 가능

3.4 명시적 vs 자동

// 명시적 commit
connection.setAutoCommit(false);
// SQL 들
connection.commit();   // 명시적

// 자동 commit (기본)
connection.setAutoCommit(true);   // 기본
// 각 SQL = 자동 commit (트랜잭션 짧음)

3.5 ILIC 의 맥락

// Commit (ILIC, Spring @Transactional)
@Service
public class ShipmentService {
    
    @Transactional
    public void processBooking(Booking b) {
        shipmentDao.add(...);
        bookingDao.update(...);
        // 메서드 끝 → Spring 이 commit
        // (예외 없으면)
    }
}

// JDBC 직접 (덜 흔함)
public void processManual() throws SQLException {
    try (Connection c = ds.getConnection()) {
        c.setAutoCommit(false);
        try {
            // SQL 들
            c.commit();   // 명시적
        } catch (Exception e) {
            c.rollback();
            throw e;
        }
    }
}
class ShipmentDao { void add(Object o) {} }
class BookingDao { void update(Object o) {} }
class Booking {}
DataSource ds;
interface DataSource { Connection getConnection() throws SQLException; }

3.6 자기 점검 답변

Commit 의 의미는?

:
1. Commit:

  • 성공, 영구 적용
  1. 의미:

    • 확정, 되돌리기 X
  2. 동작:

    • 디스크/로그/락 해제
  3. 명시/자동:

    • autoCommit

4️⃣ Rollback

4.1 Rollback

Rollback:

  트랜잭션 실패/취소:
    - 모든 변경 취소
    - 처음 상태로
    - 마치 없던 일처럼

4.2 의미

의미:

  "되돌리기":
    - "이전 상태로"
    - 변경 폐기
    - 트랜잭션 종료

4.3 발생 상황

Rollback 발생:

1. 명시적 호출 (rollback())
2. 예외 발생 (Spring 자동)
3. 제약 위반 (DB 자동)
4. 연결 끊김
5. 데드락 감지

4.4 동작

Rollback 동작:

  1. 변경된 모든 데이터 복원
     - undo log 사용
  2. 트랜잭션 로그
  3. 락 해제
  4. 트랜잭션 종료

4.5 ILIC 의 맥락

// Rollback (ILIC)
@Service
public class ShipmentService {
    
    @Transactional
    public void processBooking(Booking b) {
        try {
            shipmentDao.add(...);
            if (b.invalid()) {
                throw new IllegalArgumentException();
                // → Spring 자동 rollback (RuntimeException)
            }
            bookingDao.update(...);
        } catch (Exception e) {
            // Spring 이 자동 rollback
            throw e;
        }
    }
    
    @Transactional
    public void manualRollback(Booking b) {
        shipmentDao.add(...);
        // 비즈니스 검증
        if (b.invalid()) {
            // 명시적 rollback 마킹
            TransactionAspectSupport.currentTransactionStatus()
                .setRollbackOnly();
        }
    }
    ShipmentDao shipmentDao;
    BookingDao bookingDao;
}
class Booking { boolean invalid() { return false; } }
class ShipmentDao { void add(Object o) {} }
class BookingDao { void update(Object o) {} }
class TransactionAspectSupport {
    static TS currentTransactionStatus() { return null; }
    interface TS { void setRollbackOnly(); }
}

4.6 자기 점검 답변

Rollback 의 의미는?

:
1. Rollback:

  • 취소, 처음 상태
  1. 의미:

    • 되돌리기
  2. 발생:

    • 예외/제약/연결 끊김
  3. 동작:

    • undo log 복원

5️⃣ 트랜잭션의 끝

5.1 두 가지 끝

트랜잭션의 끝:

1. Commit (성공)
2. Rollback (실패/취소)

→ 두 가지 뿐

5.2 중간 상태 X

중간 상태 X:

  트랜잭션 진행 중:
    - 외부에 안 보임 (격리)
  
  끝 (commit/rollback):
    - 전부 보임 (commit)
    - 또는 사라짐 (rollback)

→ 중간 외부 노출 X

5.3 상태 다이어그램

상태 다이어그램:

  [시작 (BEGIN)]
      ↓
  [진행 중 (Active)]
      ↓
  ┌───┴───┐
  ↓       ↓
[Commit] [Rollback]
  (영구)  (취소)

5.4 강제 종료

강제 종료:

  - 연결 끊김 → 자동 rollback
  - 세션 강제 종료 (KILL) → rollback
  - DB 다운 → rollback
  - 타임아웃 → rollback

→ 모호한 상태 X

5.5 ILIC 의 맥락

// 트랜잭션의 끝 (ILIC)
@Service
public class ShipmentService {
    
    @Transactional
    public void example(Shipment s) {
        // 트랜잭션 시작 (BEGIN)
        
        shipmentDao.add(s);   // 진행 중
        
        // 두 갈래:
        // 1. 정상 종료 → commit
        // 2. 예외 → rollback
        
        // (메서드 끝)
    }
    
    // 중간 상태:
    // - 다른 세션 X (격리, Phase 6.4)
    // - 끝나면 전부 또는 전무
    ShipmentDao shipmentDao;
}
class Shipment {}
class ShipmentDao { void add(Shipment s) {} }

5.6 자기 점검 답변

트랜잭션의 끝 두 가지는?

:
1. 두 가지:

  • Commit/Rollback
  1. 중간 X:

    • 외부 노출 X
  2. 다이어그램:

    • 시작→진행→끝
  3. 강제:

    • 자동 rollback

6️⃣ 게시글 작성 단위

6.1 게시글 작성

게시글 작성 트랜잭션:

  작업:
    1. 게시글 INSERT
    2. 첨부 파일 INSERT
    3. 알림 INSERT
    4. 통계 UPDATE

  단위는?

6.2 한 트랜잭션 (강한 일관성)

한 트랜잭션:

  4 작업 하나로:
    - 모두 성공 or 실패
    - 일관성 강함

  단점:
    - 트랜잭션 김
    - 락 점유 길어짐

6.3 분리 (약한 일관성)

분리:

  게시글 + 첨부: 트랜잭션 1
  알림: 별도 (비동기)
  통계: 별도 (배치)

  장점:
    - 짧은 트랜잭션
    - 동시성 ↑
  단점:
    - 일시적 불일치 가능

6.4 도메인 판단

도메인 판단:

  비즈니스 요구사항:
    - 게시글 없는데 알림? X
    - 통계는 즉시? 지연 OK?

  → 도메인이 결정

6.5 ILIC 의 맥락

// 트랜잭션 단위 (ILIC 배송 예약)
@Service
public class BookingService {
    
    // 강한 일관성 (한 트랜잭션)
    @Transactional
    public void createBooking(Booking b) {
        bookingDao.add(b);           // 필수
        shipmentDao.add(...);         // 필수
        freightDao.save(...);         // 필수
        // 모두 한 단위 (이체와 같음)
    }
    
    // 분리 (비동기)
    @Transactional
    public void createBookingWithNotification(Booking b) {
        createBooking(b);   // 핵심 트랜잭션
        
        // 알림은 비동기 (별도 트랜잭션)
        notificationService.sendAsync(b);
        // → 알림 실패해도 예약은 commit
    }
    
    BookingDao bookingDao;
    ShipmentDao shipmentDao;
    FreightDao freightDao;
    NotificationService notificationService;
}
class Booking {}
class BookingDao { void add(Booking b) {} }
class ShipmentDao { void add(Object o) {} }
class FreightDao { void save(Object o) {} }
class NotificationService { void sendAsync(Booking b) {} }

6.6 자기 점검 답변

게시글 작성 시 트랜잭션 단위는?

:
1. 여러 작업:

  • INSERT 들
  1. 한 트랜잭션:

    • 강한 일관성
  2. 분리:

    • 비동기/배치
  3. 도메인:

    • 요구사항이 결정

7️⃣ "단위" 의 크기

7.1 단위 크기

"단위" 의 크기:

  너무 큼:
    - 락 점유 길게
    - 동시성 ↓
    - 데드락 위험

  너무 작음:
    - 일관성 위험
    - 부분 적용

→ 균형

7.2 크기 결정

크기 결정:

  - 비즈니스 단위
  - 일관성 요구
  - 성능 (락 시간)
  - 동시 사용자

7.3 짧은 트랜잭션 권장

짧은 트랜잭션 권장:

  - 락 시간 ↓
  - 동시성 ↑
  - 데드락 ↓
  - DB 부하 ↓

→ 가능하면 짧게

7.4 트랜잭션 안 비싼 작업 X

트랜잭션 안 비싼 작업 X:

  ❌ 트랜잭션 안에 외부 API 호출 (느림)
  ❌ 큰 파일 처리
  ❌ 메시지 큐 발행 (이벤트는 commit 후)

→ DB 작업만

7.5 ILIC 의 맥락

// 트랜잭션 크기 (ILIC)

// ❌ 너무 큼 (외부 API 포함)
@Transactional
public void badProcess(Booking b) {
    bookingDao.add(b);
    
    // 외부 API (느림, 트랜잭션 길어짐!)
    externalCustomsApi.notify(b);   // 5초 걸림
    
    shipmentDao.add(...);
    // 트랜잭션 5초 이상 → 락 길게
}

// ✓ 짧게 (외부 API 분리)
@Transactional
public void goodProcess(Booking b) {
    bookingDao.add(b);
    shipmentDao.add(...);
    // 짧은 트랜잭션
}

@Async   // 별도 (트랜잭션 후)
public void notifyCustoms(Booking b) {
    externalCustomsApi.notify(b);   // 분리
}

// → 트랜잭션 짧게 (DB 만)
ShipmentDao shipmentDao;
BookingDao bookingDao;
ExternalCustomsApi externalCustomsApi;
class Booking {}
class ShipmentDao { void add(Object o) {} }
class BookingDao { void add(Booking b) {} }
class ExternalCustomsApi { void notify(Booking b) {} }

7.6 자기 점검 답변

"단위" 의 크기 결정 기준은?

:
1. 크기:

  • 너무 크면 동시성 ↓
  1. 결정:

    • 비즈니스/성능
  2. 짧게:

    • 권장
  3. 외부 API:

    • 분리

8️⃣ JDBC autocommit

8.1 autocommit

JDBC autocommit:

  Connection 의 모드:
    - true (기본): 각 SQL = 자동 commit
    - false: 명시적 commit/rollback

  → 트랜잭션 묶음 여부

8.2 true (기본)

// autocommit = true (기본)
Connection c = ds.getConnection();
// c.getAutoCommit() == true

c.executeUpdate("INSERT ...");   // 자동 commit
c.executeUpdate("UPDATE ...");   // 자동 commit
// 각각 별 트랜잭션

8.3 false (트랜잭션 시작)

// autocommit = false (트랜잭션)
c.setAutoCommit(false);

try {
    c.executeUpdate("INSERT ...");
    c.executeUpdate("UPDATE ...");
    c.commit();   // 명시적 commit
} catch (Exception e) {
    c.rollback();
    throw e;
}

8.4 Spring 의 처리

Spring 의 처리:

  @Transactional:
    - 메서드 시작 시 autoCommit = false
    - 메서드 끝 시 commit (또는 rollback)
    - 메서드 끝나면 autoCommit 복원

→ 개발자가 직접 안 함

8.5 ILIC 의 맥락

// autocommit (ILIC)

// Spring @Transactional (권장)
@Transactional
public void process(Booking b) {
    // Spring 이 자동으로:
    // 1. autoCommit = false
    // 2. 메서드 실행
    // 3. commit (성공) or rollback (예외)
    // 4. autoCommit 복원
    bookingDao.add(b);
    shipmentDao.add(...);
}

// JDBC 직접 (덜 흔함, 부담)
public void manualProcess(Booking b) throws SQLException {
    try (Connection c = ds.getConnection()) {
        c.setAutoCommit(false);
        try {
            bookingDao.add(b);
            shipmentDao.add(...);
            c.commit();
        } catch (Exception e) {
            c.rollback();
            throw e;
        } finally {
            c.setAutoCommit(true);   // 복원
        }
    }
}
// → Spring 이 위 코드 자동
DataSource ds;
ShipmentDao shipmentDao;
BookingDao bookingDao;
class Booking {}
class ShipmentDao { void add(Object o) {} }
class BookingDao { void add(Booking b) {} }
interface DataSource { Connection getConnection() throws SQLException; }

8.6 자기 점검 답변

JDBC autocommit 과의 관계는?

:
1. autocommit:

  • 각 SQL = 자동 commit
  1. true (기본):

    • 짧은 트랜잭션
  2. false:

    • 명시적 묶음
  3. Spring:

    • 자동 처리

9️⃣ Spring @Transactional

9.1 @Transactional

@Transactional:

  Spring 의 선언적 트랜잭션:
    - 메서드/클래스에 붙임
    - AOP 가 처리
    - 코드 깔끔

9.2 동작

@Service
public class ShipmentService {
    
    @Transactional   // 트랜잭션
    public void process(Booking b) {
        // 1. AOP 가 트랜잭션 시작 (autoCommit=false)
        bookingDao.add(b);
        shipmentDao.add(...);
        // 2. AOP 가 commit (정상) or rollback (예외)
    }
}

9.3 옵션

@Transactional 옵션:

  - propagation: 전파 (REQUIRED 기본)
  - isolation: 격리 수준
  - timeout: 타임아웃
  - readOnly: 읽기 전용
  - rollbackFor: 롤백 예외 지정

9.4 RuntimeException 자동 rollback

자동 rollback:

  RuntimeException / Error:
    - Spring 자동 rollback

  Checked Exception:
    - 자동 rollback X
    - rollbackFor 명시 필요

9.5 ILIC 의 맥락

// Spring @Transactional (ILIC)
@Service
public class ShipmentService {
    
    @Transactional
    public void createBooking(Booking b) {
        bookingDao.add(b);
        shipmentDao.add(...);
        // RuntimeException → 자동 rollback
    }
    
    @Transactional(readOnly = true)
    public List<Shipment> findAll() {
        return shipmentDao.findAll();
        // 읽기 전용 (최적화)
    }
    
    @Transactional(timeout = 30)
    public void heavyOperation() {
        // 30초 타임아웃
    }
    
    @Transactional(rollbackFor = IOException.class)
    public void withCheckedException() throws IOException {
        // IOException 도 rollback
    }
    
    ShipmentDao shipmentDao;
    BookingDao bookingDao;
}
class Booking {}
class Shipment {}
class ShipmentDao {
    void add(Object o) {}
    java.util.List<Shipment> findAll() { return null; }
}
class BookingDao { void add(Booking b) {} }

9.6 자기 점검 답변

Spring @Transactional 은?

:
1. @Transactional:

  • 선언적 트랜잭션
  1. AOP:

    • 자동 처리
  2. 옵션:

    • propagation/isolation/...
  3. 자동 rollback:

    • RuntimeException

🎯 핵심 요약 — 3줄 정리

1. 트랜잭션

  • 여러 작업을 한 단위로 묶음 (전부 or 전무)
  • 계좌 이체: 출금 + 입금 = 한 트랜잭션

2. Commit / Rollback

  • Commit: 모든 변경 영구 적용
  • Rollback: 모든 변경 취소 (처음 상태)
  • 중간 상태는 외부에 노출 X

3. 단위의 크기와 Spring

  • 너무 크면 동시성 ↓ (락), 너무 작으면 일관성 위험
  • Spring @Transactional 이 자동 처리 (AOP)

📚 다음으로...

Unit 6.2 — Atomicity (원자성) ★깊이

이번 Unit에서 트랜잭션 기본을 봤다면, 다음은 Atomicity (★ 깊이 파기).

  • 전부 성공 / 전부 실패
  • 자바 Atomic 과 차이
  • 부분 성공 허용 (Saga)

Phase 6 진행 상황

💎 Phase 6 — 트랜잭션과 ACID
  ✅ Unit 6.1 트랜잭션이란 ← 여기
  ⏭ Unit 6.2 Atomicity ★깊이
  ⏭ Unit 6.3 Consistency ★깊이
  ⏭ Unit 6.4 Isolation ★깊이
  ⏭ Unit 6.5 Durability ★깊이
  ⏭ Unit 6.6 Commit 이전 동시성 ★깊이

6주차 누적 진행

🧪 Part A (9 Unit) ✅
💾 Part B — DB 접근의 진화
  ✅ Phase 3 — JDBC (3)
  ✅ Phase 4 — Connection Pool (4)
  ✅ Phase 5 — DataSource (4)
  💎 Phase 6 — 트랜잭션 ACID (1/6)

총: 21/28 Unit

💎 Phase 6 시작 — 트랜잭션 ACID

profile
Software Developer

0개의 댓글