7주차 Unit 6.3 — 사용 전후 비교

Psj·2026년 6월 5일

F-lab

목록 보기
233/239

Unit 6.3 — 사용 전후 비교

F-LAB JAVA · 7주차 · Phase 6 · PlatformTransactionManager
🏆 Phase 6 완주 — 점진적 추상화의 흐름


📌 학습 목표

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

  • 사용 전후 비교 개요는?
  • Before — 수동 트랜잭션 코드는?
  • After 1 — PlatformTransactionManager 직접 코드는?
  • After 2 — TransactionTemplate (람다) 코드는?
  • After 3 — @Transactional 미리보기 는?
  • 단계별 코드 비교 (한눈에) 는?
  • 5+6주차 학습 응축 의미는?
  • 진화의 의미 는?
  • Phase 7 (@Transactional ★★★) 예고 는?

🎯 핵심 한 문장

수동 트랜잭션 (begin/commit/rollback 직접 = 15 줄) → PlatformTransactionManager 직접 사용 (인터페이스 의존 = 12 줄) → TransactionTemplate (람다 + try/catch 자동 = 5 줄) → @Transactional (어노테이션 1줄 + AOP) 의 4 단계 진화로 코드 양은 15 → 1 로 줄고 SoC / 안전성 / 일관성 모두 점진적으로 향상되며, 이 진화의 마지막 정점이 Phase 7 의 @Transactional + 프록시 + AOP ★★★ 학습이다.
트랜잭션 처리의 진화는 4 단계 — 각 단계마다 코드 양은 줄고 추상화 수준은 높아진다.
(1) Before (수동 트랜잭션, Phase 5)tx.begin / try / commit / catch / rollback / finally / close 매번 작성, 15 줄 보일러플레이트, SoC 위반 / 함정 위험.
(2) After 1 (PlatformTransactionManager 직접) — 인터페이스 의존 (DIP), 어떤 TM 이든 같은 코드, 12 줄 (수동 대비 약간 개선), 여전히 명시적 commit/rollback.
(3) After 2 (TransactionTemplate) — 람다 (Callback) 로 비즈니스 전달, 5 줄 (try/catch/finally 자동), 5주차 템플릿+전략 패턴 / 6주차 JdbcTemplate 와 같은 정신.
(4) After 3 (@Transactional, Phase 7 ★★★) — 어노테이션 1 줄 + AOP/프록시 자동, 완전 자동화, SoC 완벽, 현대 표준.
진화의 의미 — 5주차 디자인 패턴 (DI/DIP/OCP/템플릿+전략) + 6주차 DataSource 추상화 + 자바 진영 추상화 정신 의 결정체로, ILIC 의 1020 메서드가 모두 @Transactional 어노테이션 1 줄만으로 안전하게 동작하는 게 이 진화의 결과다.

비유 — 자동차의 진화

트랜잭션 처리 진화 = 자동차 진화:

[Before] 손수레 (수동 트랜잭션):
  - 모든 부품 직접 조립
  - 매번 같은 과정
  - 실수 위험
  - 운반: 가능하지만 부담

[After 1] 수동 변속기 자동차 (PlatformTM 직접):
  - 부품 표준화 (인터페이스)
  - 운전법 같음 (어떤 차든)
  - 하지만 변속 직접
  - 운반: 더 효율적

[After 2] 자동 변속기 (TransactionTemplate):
  - 변속 자동
  - 운전자: 가속 / 핸들만
  - 람다 (Callback) = 운전자 의도
  - 운반: 편함

[After 3] 자율주행 (@Transactional):
  - 어노테이션 1줄 = "목적지"
  - 모든 동작 자동
  - 완벽한 추상화
  - 운반: 최상

진화의 의미:
  - 5주차 (디자인) + 6주차 (DataSource) 정신
  - 인터페이스 추상화
  - 점진적 자동화
  - 5+6+7주차 응축

ILIC:
  - 1020 메서드 = 모두 @Transactional 1줄
  - 박승제 + 1 풀스택 = 운영 가능
  - 자동화의 결과

→ 4 단계 진화, 코드 15 → 1, 점진적 추상화, @Transactional 정점.


🧭 9개 섹션 로드맵

1. 사용 전후 비교 개요
2. Before — 수동 트랜잭션
3. After 1 — PlatformTransactionManager 직접
4. After 2 — TransactionTemplate (람다)
5. After 3 — @Transactional 미리보기
6. 단계별 코드 비교 (한눈에)
7. 5+6주차 학습 응축
8. 진화의 의미
9. Phase 6 완주 + Phase 7 ★★★ 예고

1️⃣ 사용 전후 비교 개요

1.1 4 단계 진화

4 단계 진화:

  ① Before (Phase 5):
     - 수동 트랜잭션
     - tx.begin / commit / rollback
     - 15 줄

  ② After 1 (Phase 6.1):
     - PlatformTransactionManager 직접
     - 인터페이스 의존
     - 12 줄

  ③ After 2 (Phase 6.1-2):
     - TransactionTemplate
     - 람다
     - 5 줄

  ④ After 3 (Phase 7):
     - @Transactional
     - 어노테이션
     - 1 줄

1.2 코드 양의 진화

코드 양:

  Before:    15 줄 (트랜잭션) + 3 줄 (비즈니스)
  After 1:   12 줄 (트랜잭션) + 3 줄 (비즈니스)
  After 2:    5 줄 (트랜잭션) + 3 줄 (비즈니스)
  After 3:    1 줄 (@Transactional) + 3 줄 (비즈니스)

→ 15 → 1
→ 93% 감소

1.3 추상화 수준 진화

추상화 수준:

  Before:
    - 가장 저수준
    - JDBC 직접 또는 JPA 직접
    - 트랜잭션 객체 명시

  After 1:
    - PlatformTM 인터페이스
    - 구현체 모름
    - 5주차 DIP

  After 2:
    - 람다 + 자동
    - 5주차 템플릿+전략

  After 3:
    - 어노테이션 + AOP
    - 완전 자동
    - 5주차 프록시

1.4 ILIC 의 맥락

ILIC = After 3 사용

ILIC 의 모든 1020 메서드:
  - @Transactional 어노테이션
  - 1 줄
  - 비즈니스만

  수동 (Before) 이었으면:
    - 15,000 줄+ 트랜잭션 코드
    - 함정 위험
    - 운영 사고

  @Transactional 덕분:
    - 1020 줄
    - 안전
    - 자동

→ 93% 절약 + 안전

1.5 자기 점검 답변

사용 전후 비교 개요는?

:
1. 4 단계:

  • Before/After1/After2/After3
  1. 코드:

    • 15 → 1
  2. 추상화:

    • 점진적
  3. 현재 표준:

    • @Transactional

2️⃣ Before — 수동 트랜잭션

2.1 수동 트랜잭션 (JPA 직접)

// Before: 수동 트랜잭션
@Service
public class ShipmentService {
    @Autowired EntityManagerFactory emf;
    
    public void processShipment(Long id) {
        EntityManager em = emf.createEntityManager();          // ① 자원
        EntityTransaction tx = em.getTransaction();              // ②
        
        try {
            tx.begin();                                          // ③ 시작
            
            // === 비즈니스 (3 줄) ===
            Shipment s = em.find(Shipment.class, id);
            s.markAsShipped();
            em.merge(s);
            // === 비즈니스 끝 ===
            
            tx.commit();                                         // ④ 커밋
        } catch (Exception e) {
            if (tx.isActive()) {                                  // ⑤ 안전
                tx.rollback();                                    // ⑥ 롤백
            }
            throw new RuntimeException(e);                       // ⑦
        } finally {
            em.close();                                          // ⑧ 자원
        }
    }
}
// → 15 줄 트랜잭션 코드
// → 3 줄 비즈니스
class Shipment { void markAsShipped() {} }
EntityManagerFactory emf;
class EntityManagerFactory { EntityManager createEntityManager() { return null; } }
class EntityManager {
    EntityTransaction getTransaction() { return null; }
    <T> T find(Class<T> c, Object id) { return null; }
    <T> T merge(T t) { return null; }
    void close() {}
}
class EntityTransaction {
    void begin() {}
    void commit() {}
    void rollback() {}
    boolean isActive() { return false; }
}
@interface Service {}
@interface Autowired {}

2.2 문제점 종합 (Phase 5 복습)

문제점 (Phase 5):

  1. SoC 위반:
     - 비즈니스 (3 줄) + 인프라 (15 줄)
     - 한 메서드

  2. 보일러플레이트:
     - 매 메서드 같은 패턴
     - 1020 메서드 × 12 줄 = 12,240 줄

  3. 함정 위험:
     - rollback 누락
     - close 누락
     - 일관성 ↓

  4. 의도 모호:
     - 비즈니스 코드 묻힘
     - 가독성 ↓

2.3 ILIC 의 부담 (가정)

ILIC 의 부담 (수동, 가정)

  102 테이블 × 평균 10 메서드 = 1020 메서드

  각 메서드:
    - 비즈니스: 3-10 줄
    - 트랜잭션: 12-15 줄

  총:
    - 비즈니스: 약 6,000 줄
    - 트랜잭션: 약 13,000 줄

  비율:
    - 트랜잭션 > 비즈니스
    - 본말 전도

  유지보수:
    - 모든 메서드 트랜잭션 확인
    - 시간 폭증
    - 실수 위험

2.4 자기 점검 답변

Before — 수동 트랜잭션 코드는?

:
1. 수동:

  • tx.begin/commit/rollback
  1. 줄 수:

    • 15 줄
  2. 문제:

    • SoC / 보일러 / 함정
  3. ILIC:

    • 13,000 줄

3️⃣ After 1 — PlatformTransactionManager 직접

3.1 PlatformTM 직접 사용

// After 1: PlatformTransactionManager 직접
@Service
public class ShipmentService {
    @Autowired PlatformTransactionManager tm;   // 인터페이스
    @Autowired ShipmentRepository repo;
    
    public void processShipment(Long id) {
        TransactionStatus status = tm.getTransaction(
            new DefaultTransactionDefinition()
        );                                              // ① 시작
        
        try {
            // === 비즈니스 ===
            Shipment s = repo.findById(id).orElseThrow();
            s.markAsShipped();
            // === 비즈니스 끝 ===
            
            tm.commit(status);                          // ② 커밋
        } catch (Exception e) {
            tm.rollback(status);                        // ③ 롤백
            throw new RuntimeException(e);
        }
    }
}
// → 12 줄 트랜잭션
// → 인터페이스 의존
class Shipment { void markAsShipped() {} }
ShipmentRepository repo;
interface ShipmentRepository { java.util.Optional<Shipment> findById(Long id); }
class PlatformTransactionManager {
    TransactionStatus getTransaction(TransactionDefinition d) { return null; }
    void commit(TransactionStatus s) {}
    void rollback(TransactionStatus s) {}
}
PlatformTransactionManager tm;
class TransactionStatus {}
class TransactionDefinition {}
class DefaultTransactionDefinition extends TransactionDefinition {}
@interface Service {}
@interface Autowired {}

3.2 개선점

개선점:

  1. 인터페이스 의존:
     - PlatformTransactionManager 만
     - 구현체 모름
     - 5주차 DIP ✓

  2. 자원 관리 ↓:
     - em.close() X (TM 이 처리)

  3. finally 불필요:
     - TM 이 내부적으로 자원 정리

  4. 일관 인터페이스:
     - JDBC / JPA / Hibernate 모두 같음

  하지만:
    - 여전히 명시적 commit / rollback
    - try / catch 필요
    - 12 줄

3.3 남은 문제

남은 문제:

  1. 여전히 보일러플레이트:
     - 매 메서드 try/catch
     - 12 줄 반복

  2. 인지 부담:
     - try / catch / rollback / throw
     - 매번 작성

  3. SoC 부분적:
     - 인프라 코드 줄었지만 여전히 있음

→ 다음 단계 필요 (TransactionTemplate)

3.4 코드 비교 (Before vs After 1)

Before:
  EntityManager em = emf.createEntityManager();    ← 자원
  EntityTransaction tx = em.getTransaction();       ← 자원
  try {
      tx.begin();                                   ← 시작
      // 비즈니스
      tx.commit();                                  ← 커밋
  } catch (Exception e) {
      if (tx.isActive()) tx.rollback();            ← 안전 + 롤백
      throw new RuntimeException(e);
  } finally {
      em.close();                                   ← 자원 정리
  }

After 1:
  TransactionStatus status = tm.getTransaction(...);  ← 시작
  try {
      // 비즈니스
      tm.commit(status);                              ← 커밋
  } catch (Exception e) {
      tm.rollback(status);                            ← 롤백
      throw new RuntimeException(e);
  }
  // finally 없음 (TM 이 처리)

→ 자원 / finally 자동
→ 하지만 try/catch 여전

3.5 ILIC 의 맥락

// ILIC 의 After 1 (만약 사용했다면)

@Service
public class ShipmentService {
    @Autowired PlatformTransactionManager tm;
    @Autowired ShipmentRepository repo;
    
    public Shipment get(Long id) {
        DefaultTransactionDefinition def = new DefaultTransactionDefinition();
        def.setReadOnly(true);   // 읽기 전용
        
        TransactionStatus status = tm.getTransaction(def);
        try {
            Shipment s = repo.findById(id).orElseThrow();
            tm.commit(status);
            return s;
        } catch (Exception e) {
            tm.rollback(status);
            throw new RuntimeException(e);
        }
    }
}

// → 1020 메서드 × 12 줄 = 12,240 줄 보일러플레이트
// → 여전히 부담
// → 다음 단계 필요
class Shipment {}
ShipmentRepository repo;
interface ShipmentRepository { java.util.Optional<Shipment> findById(Long id); }
class PlatformTransactionManager {
    TransactionStatus getTransaction(TransactionDefinition d) { return null; }
    void commit(TransactionStatus s) {}
    void rollback(TransactionStatus s) {}
}
PlatformTransactionManager tm;
class TransactionStatus {}
class TransactionDefinition {}
class DefaultTransactionDefinition extends TransactionDefinition { void setReadOnly(boolean b) {} }
@interface Service {}
@interface Autowired {}

3.6 자기 점검 답변

After 1 — PlatformTransactionManager 직접 코드는?

:
1. PlatformTM:

  • 인터페이스 의존
  1. 줄 수:

    • 12 줄
  2. 개선:

    • 자원 자동
  3. 남은 문제:

    • try/catch 여전

4️⃣ After 2 — TransactionTemplate (람다)

4.1 TransactionTemplate 사용

// After 2: TransactionTemplate
@Service
public class ShipmentService {
    @Autowired TransactionTemplate transactionTemplate;
    @Autowired ShipmentRepository repo;
    
    public void processShipment(Long id) {
        transactionTemplate.executeWithoutResult(status -> {
            // === 비즈니스만 ===
            Shipment s = repo.findById(id).orElseThrow();
            s.markAsShipped();
            // === 비즈니스 끝 ===
        });
        // 트랜잭션 자동:
        // - 시작 / commit / rollback / 자원 정리
    }
}
// → 5 줄 (lambda 포함)
// → try/catch 자동
class Shipment { void markAsShipped() {} }
ShipmentRepository repo;
interface ShipmentRepository { java.util.Optional<Shipment> findById(Long id); }
class TransactionTemplate {
    void executeWithoutResult(java.util.function.Consumer<TransactionStatus> c) {}
    <T> T execute(java.util.function.Function<TransactionStatus, T> f) { return null; }
}
TransactionTemplate transactionTemplate;
class TransactionStatus {}
@interface Service {}
@interface Autowired {}

4.2 람다의 마법

람다의 마법:

  변하지 않는 부분 (TransactionTemplate):
    - 트랜잭션 시작
    - try / catch / finally
    - commit / rollback
    - 자원 정리

  변하는 부분 (람다):
    - 비즈니스 로직만

→ 5주차 템플릿+전략 패턴
→ 6주차 JdbcTemplate 와 같은 정신

4.3 반환값 있을 때

// 반환값 있을 때 (execute)
public Shipment getShipment(Long id) {
    return transactionTemplate.execute(status -> {
        return repo.findById(id).orElseThrow();
    });
}

// 또는 (Java 17+)
public Shipment getShipment(Long id) {
    return transactionTemplate.execute(status -> 
        repo.findById(id).orElseThrow()
    );
}
class Shipment {}
ShipmentRepository repo;
interface ShipmentRepository { java.util.Optional<Shipment> findById(Long id); }
class TransactionTemplate {
    <T> T execute(java.util.function.Function<TransactionStatus, T> f) { return null; }
}
TransactionTemplate transactionTemplate;
class TransactionStatus {}

4.4 명시적 rollback

// 명시적 rollback (조건부)
transactionTemplate.executeWithoutResult(status -> {
    Shipment s = repo.findById(id).orElseThrow();
    
    if (!s.canProcess()) {
        status.setRollbackOnly();   // ← rollback 예약
        return;
    }
    
    s.process();
});
// 자동:
// - rollbackOnly 면 commit 시 rollback
class Shipment {
    boolean canProcess() { return false; }
    void process() {}
}
ShipmentRepository repo;
interface ShipmentRepository { java.util.Optional<Shipment> findById(Long id); }
class TransactionTemplate {
    void executeWithoutResult(java.util.function.Consumer<TransactionStatus> c) {}
}
TransactionTemplate transactionTemplate;
class TransactionStatus { void setRollbackOnly() {} }
Long id;

4.5 TransactionTemplate 의 내부 (재확인)

// TransactionTemplate 의 동작 (개념)
public <T> T execute(TransactionCallback<T> action) {
    TransactionStatus status = transactionManager.getTransaction(definition);
    
    T result;
    try {
        result = action.doInTransaction(status);   // ← 람다 호출
    } catch (Exception e) {
        transactionManager.rollback(status);
        throw e;
    }
    
    transactionManager.commit(status);
    return result;
}
// 5주차 템플릿+전략 패턴 완벽 적용
class TransactionCallback<T> { T doInTransaction(TransactionStatus s) { return null; } }
class PlatformTransactionManager {
    TransactionStatus getTransaction(Object d) { return null; }
    void commit(TransactionStatus s) {}
    void rollback(TransactionStatus s) {}
}
class TransactionStatus {}
PlatformTransactionManager transactionManager;
Object definition;

4.6 6주차 JdbcTemplate 와 같은 정신

6주차 JdbcTemplate ↔ 7주차 TransactionTemplate:

JdbcTemplate (6주차):
  - 변하지 않는 부분: Connection / Statement / ResultSet
  - 변하는 부분: SQL / RowMapper (람다)
  - 자원 관리 자동

TransactionTemplate (7주차):
  - 변하지 않는 부분: begin / commit / rollback / close
  - 변하는 부분: 비즈니스 (람다)
  - 트랜잭션 자동

→ 정확히 같은 패턴
→ 5주차 템플릿+전략 + 3주차 람다

4.7 개선점

개선점 (After 1 → After 2):

  1. 코드 ↓:
     - 12 줄 → 5 줄

  2. try/catch 제거:
     - 자동 처리

  3. 가독성 ↑:
     - 비즈니스 명확
     - 람다 = 의도 명확

  4. 람다 활용:
     - 3주차 함수형
     - 5주차 패턴

  하지만:
    - 메서드 시그니처 노이즈 (Consumer / Function)
    - 람다 안에서 예외 처리 미묘
    - 메서드 전체 트랜잭션 아닐 때만 진가

4.8 ILIC 의 맥락 (가끔 활용)

// ILIC 의 TransactionTemplate 활용 (배치 등)

@Service
public class ShipmentBatchService {
    @Autowired TransactionTemplate transactionTemplate;
    @Autowired ShipmentRepository repo;
    
    // 배치: 개별 트랜잭션 (실패해도 다른 거 계속)
    public void processBatch(List<Long> ids) {
        for (Long id : ids) {
            try {
                transactionTemplate.executeWithoutResult(status -> {
                    Shipment s = repo.findById(id).orElseThrow();
                    s.process();
                });
                // 개별 트랜잭션 (1건 실패해도 나머지 계속)
            } catch (Exception e) {
                log.error("Failed processing {}", id, e);
            }
        }
    }
}

// → ILIC 도 가끔 사용 (배치 / 세밀 제어)
// → 일반은 @Transactional 표준
class Shipment { void process() {} }
ShipmentRepository repo;
interface ShipmentRepository { java.util.Optional<Shipment> findById(Long id); }
class TransactionTemplate {
    void executeWithoutResult(java.util.function.Consumer<TransactionStatus> c) {}
}
TransactionTemplate transactionTemplate;
class TransactionStatus {}
org.slf4j.Logger log;
@interface Service {}
@interface Autowired {}

4.9 자기 점검 답변

After 2 — TransactionTemplate (람다) 코드는?

:
1. TransactionTemplate:

  • 람다 (Callback)
  1. 줄 수:

    • 5 줄
  2. 패턴:

    • 5주차 템플릿+전략
  3. 6주차 JdbcTemplate:

    • 같은 정신

5️⃣ After 3 — @Transactional 미리보기

5.1 @Transactional 사용

// After 3: @Transactional
@Service
public class ShipmentService {
    @Autowired ShipmentRepository repo;
    
    @Transactional   // ← 이거 1 줄!
    public void processShipment(Long id) {
        // === 비즈니스만 ===
        Shipment s = repo.findById(id).orElseThrow();
        s.markAsShipped();
        // === 비즈니스 끝 ===
    }
    // 자동:
    // - 트랜잭션 시작
    // - 메서드 실행
    // - 정상 → commit
    // - 예외 → rollback
    // - 자원 정리
}
// → 1 줄
// → 비즈니스만
class Shipment { void markAsShipped() {} }
ShipmentRepository repo;
interface ShipmentRepository { java.util.Optional<Shipment> findById(Long id); }
@interface Service {}
@interface Autowired {}
@interface Transactional {}

5.2 어노테이션의 마법

어노테이션의 마법:

  @Transactional:
    - 단순 어노테이션 (메타데이터)
    - 동작 X (자체로는)

  Spring 의 AOP / 프록시:
    - 어노테이션 감지
    - 프록시 객체 생성
    - 호출 시 트랜잭션 자동

→ 다음 Phase 7 ★★★ 상세

5.3 호출 흐름

호출 흐름:

  ① 클라이언트:
     shipmentService.processShipment(1L);
  
  ② Spring 의 프록시 (Spring 이 생성):
     - 진짜 ShipmentService 의 자식 또는 인터페이스 구현
     - 호출 가로채기 (AOP)
  
  ③ 프록시:
     - PlatformTransactionManager.getTransaction()
     - 진짜 메서드 호출
  
  ④ 진짜 메서드:
     - 비즈니스 로직
  
  ⑤ 프록시:
     - 정상 → tm.commit()
     - 예외 → tm.rollback()
     - 자원 정리

→ 모두 자동

5.4 옵션

// @Transactional 의 옵션 (다양)
@Transactional(
    propagation = Propagation.REQUIRED,        // 전파
    isolation = Isolation.READ_COMMITTED,       // 격리
    timeout = 30,                                // 타임아웃 (초)
    readOnly = false,                            // 읽기 전용
    rollbackFor = {Exception.class}              // 어떤 예외 시 rollback
)
public void process() {
    // ...
}

// 모든 옵션이 @Transactional 어노테이션 1줄에
@interface Transactional {
    Propagation propagation() default Propagation.REQUIRED;
    Isolation isolation() default Isolation.DEFAULT;
    int timeout() default -1;
    boolean readOnly() default false;
    Class<?>[] rollbackFor() default {};
}
enum Propagation { REQUIRED }
enum Isolation { DEFAULT, READ_COMMITTED }

5.5 5가지 함정 (Phase 7 예고)

5가지 함정 (Phase 7):

  1. private 메서드:
     - 프록시 적용 X
     - @Transactional 무시

  2. self-invocation:
     - 같은 클래스 내 호출
     - 프록시 우회
     - 무시

  3. checked exception:
     - 기본 rollback X
     - rollbackFor 명시 필요

  4. 트랜잭션 전파:
     - REQUIRED / REQUIRES_NEW / NESTED 등
     - 7가지

  5. readOnly:
     - 진짜 읽기 전용?
     - 최적화 X 케이스

5.6 ILIC 의 표준

// ILIC 의 @Transactional 표준
@Service
public class ShipmentService {
    @Autowired ShipmentRepository repo;
    
    // 쓰기
    @Transactional
    public void process(Long id) {
        Shipment s = repo.findById(id).orElseThrow();
        s.markAsShipped();
    }
    
    // 읽기 전용 (최적화)
    @Transactional(readOnly = true)
    public List<Shipment> findAll() {
        return repo.findAll();
    }
    
    // 새 트랜잭션 (로그 등)
    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public void logEvent(Long id, String event) {
        eventLogRepo.save(new EventLog(id, event));
    }
}

// → 102 테이블 × 1020 메서드 모두 이 패턴
// → 1020 줄 (어노테이션)
class Shipment { void markAsShipped() {} }
ShipmentRepository repo;
interface ShipmentRepository {
    java.util.Optional<Shipment> findById(Long id);
    java.util.List<Shipment> findAll();
}
class EventLog { EventLog(Long id, String e) {} }
EventLogRepository eventLogRepo;
interface EventLogRepository { void save(EventLog e); }
@interface Service {}
@interface Autowired {}
@interface Transactional {
    boolean readOnly() default false;
    Propagation propagation() default Propagation.REQUIRED;
}
enum Propagation { REQUIRED, REQUIRES_NEW }

5.7 자기 점검 답변

After 3 — @Transactional 미리보기는?

:
1. @Transactional:

  • 어노테이션 1 줄
  1. 자동:

    • 트랜잭션 모두
  2. AOP / 프록시:

    • Phase 7 ★★★
  3. 5가지 함정:

    • Phase 7.3 ★

6️⃣ 단계별 코드 비교 (한눈에)

6.1 4 단계 코드 비교

═══════════════════════════════════
Before (수동) — 15 줄
═══════════════════════════════════
public void process(Long id) {
    EntityManager em = emf.createEntityManager();
    EntityTransaction tx = em.getTransaction();
    try {
        tx.begin();
        Shipment s = em.find(Shipment.class, id);
        s.markAsShipped();
        em.merge(s);
        tx.commit();
    } catch (Exception e) {
        if (tx.isActive()) tx.rollback();
        throw new RuntimeException(e);
    } finally {
        em.close();
    }
}

═══════════════════════════════════
After 1 (PlatformTM) — 12 줄
═══════════════════════════════════
public void process(Long id) {
    TransactionStatus status = tm.getTransaction(
        new DefaultTransactionDefinition()
    );
    try {
        Shipment s = repo.findById(id).orElseThrow();
        s.markAsShipped();
        tm.commit(status);
    } catch (Exception e) {
        tm.rollback(status);
        throw new RuntimeException(e);
    }
}

═══════════════════════════════════
After 2 (TransactionTemplate) — 5 줄
═══════════════════════════════════
public void process(Long id) {
    transactionTemplate.executeWithoutResult(status -> {
        Shipment s = repo.findById(id).orElseThrow();
        s.markAsShipped();
    });
}

═══════════════════════════════════
After 3 (@Transactional) — 1 줄
═══════════════════════════════════
@Transactional
public void process(Long id) {
    Shipment s = repo.findById(id).orElseThrow();
    s.markAsShipped();
}

6.2 줄 수 진화

줄 수 진화:

  Before:    15 줄 (트랜잭션) +  3 줄 (비즈니스) = 18 줄
  After 1:   12 줄 (트랜잭션) +  3 줄 (비즈니스) = 15 줄
  After 2:    3 줄 (트랜잭션) +  2 줄 (비즈니스, 람다) =  5 줄
  After 3:    1 줄 (@Transactional) +  2 줄 (비즈니스) =  3 줄

→ 18 → 3
→ 83% 감소

6.3 ILIC 의 규모 (1020 메서드)

ILIC 의 규모 (1020 메서드):

  Before:
    1020 × 15 = 15,300 줄 (트랜잭션)
    + 1020 × 3 = 3,060 줄 (비즈니스)
    총: 18,360 줄

  After 1:
    1020 × 12 = 12,240 줄 (트랜잭션)
    + 1020 × 3 = 3,060 줄 (비즈니스)
    총: 15,300 줄

  After 2:
    1020 × 3 = 3,060 줄 (트랜잭션)
    + 1020 × 2 = 2,040 줄 (비즈니스, 람다)
    총: 5,100 줄

  After 3:
    1020 × 1 = 1,020 줄 (@Transactional)
    + 1020 × 2 = 2,040 줄 (비즈니스)
    총: 3,060 줄

  → 18,360 → 3,060
  → 83% 절약
  → 약 15,000 줄 줄임!

6.4 SoC 비교

단계비즈니스인프라SoC
Before3 줄15 줄❌ (인프라 > 비즈니스)
After 13 줄12 줄
After 22 줄3 줄
After 32 줄0 줄 (어노테이션만)

6.5 안전성 비교

단계rollback 누락close 누락일관성
Before위험위험
After 1위험 (try/catch 수동)자동
After 2자동 (TransactionTemplate)자동
After 3자동 (@Transactional)자동

6.6 자기 점검 답변

단계별 코드 비교 (한눈에) 는?

:
1. 줄 수:

  • 18 → 15 → 5 → 3
  1. ILIC:

    • 18,000 → 3,000 줄
  2. SoC:

    • 점진적 ↑
  3. 안전성:

    • 점진적 ↑

7️⃣ 5+6주차 학습 응축

7.1 5주차 + 6주차 + 7주차 응축

5주차 + 6주차 + 7주차 응축:

5주차 (디자인 패턴):
  - DI / DIP / OCP
  - 템플릿+전략
  - 프록시
  - SoC

6주차 (DB 접근):
  - DataSource 추상화
  - ACID
  - JdbcTemplate

7주차 Part B (트랜잭션):
  - PlatformTransactionManager
  - TransactionTemplate
  - @Transactional (프록시)
  - 5+6주차 정신 응축

7.2 5주차 패턴 매핑

5주차 패턴 매핑:

  - DI:
    @Autowired PlatformTransactionManager tm;
    어노테이션 1줄

  - DIP:
    PlatformTransactionManager (인터페이스 의존)
    구현체 모름

  - OCP:
    구현체 교체 가능
    JpaTM / DataSourceTM 등

  - 템플릿+전략:
    TransactionTemplate (템플릿)
    람다 (전략)

  - 프록시:
    @Transactional 의 동작
    Phase 7 ★★★

→ 5주차 모든 패턴 응축

7.3 6주차 정신 매핑

6주차 정신 매핑:

  6주차 DataSource:
    - 인터페이스 + 구현
    - HikariDataSource 등

  7주차 PlatformTM:
    - 인터페이스 + 구현
    - JpaTransactionManager 등

  → 정확히 같은 패턴

  6주차 JdbcTemplate:
    - 자원 관리 자동

  7주차 TransactionTemplate:
    - 트랜잭션 관리 자동

  → 같은 정신

7.4 학습의 누적 가치

학습의 누적 가치:

  1주차 → 7주차:
    - 자바 OOP
    - JVM
    - 함수형 (3주차)
    - 동시성
    - 디자인 패턴 (5주차)
    - DB 접근 (6주차)
    - ORM + 트랜잭션 (7주차)

  각 주차가 다음 주차의 기반:
    - 3주차 → 람다 (TransactionTemplate)
    - 5주차 → 디자인 패턴 (PlatformTM)
    - 6주차 → DataSource (PlatformTM)

→ 7주차 = 모든 학습의 정점

7.5 박승제의 학습 흐름

박승제의 학습 흐름

1주차 OOP →
  2주차 JVM →
    3주차 람다 →
      4주차 동시성 →
        5주차 디자인 패턴 →
          6주차 DB 접근 →
            7주차 ORM + 트랜잭션 (지금)

  각 주차 단단히 →
  7주차 깊은 이해
  
  Phase 7 (@Transactional ★★★):
    - 5주차 프록시 활용
    - 6주차 PlatformTM 위에
    - 7주차 정점

→ 면접 / 운영 / 코드 리뷰
→ 박승제의 자산

7.6 ILIC 의 결정체

ILIC = 5+6+7주차 결정체

ILIC 의 코드:
  @Service
  public class ShipmentService {
      @Autowired ShipmentRepository repo;
      
      @Transactional
      public void process(Long id) {
          Shipment s = repo.findById(id).orElseThrow();
          s.markAsShipped();
      }
  }

  내부 동작:
    - 5주차: @Service 빈, @Autowired DI, 프록시
    - 6주차: HikariCP, DataSource, JDBC
    - 7주차: Spring Data JPA, JpaTransactionManager,
              @Transactional, EntityManager

  모든 학습이 이 1 메서드에 응축
  단순하지만 깊음

→ 자바 백엔드의 정점

7.7 자기 점검 답변

5+6주차 학습 응축 의미는?

:
1. 5주차:

  • 디자인 패턴 (DI/DIP/OCP/템플릿+전략/프록시)
  1. 6주차:

    • DataSource / JdbcTemplate
  2. 7주차 Part B:

    • 모든 응축
  3. 결정체:

    • @Transactional 1 줄

8️⃣ 진화의 의미

8.1 진화의 의미

진화의 의미:

  자바 진영의 정신:
    - 추상화 + 표준 + 자동화
    - 점진적 진화
    - DI / DIP / OCP

  트랜잭션의 진화:
    - 수동 → 인터페이스 → 람다 → 어노테이션
    - 코드 ↓ + 안전 ↑ + SoC ✓

  추상화의 가치:
    - 보일러플레이트 ↓
    - 비즈니스 집중
    - 실수 ↓

8.2 추상화의 비용

추상화의 비용:

  장점:
    - 위 가치

  비용:
    - "마법" 느낌
    - 내부 모르면 디버깅 ↓
    - 함정 (Phase 7)
    - 학습곡선

  대처:
    - 깊은 이해 (이번 학습)
    - 5+6+7주차 정신

8.3 다른 진화 사례

다른 진화 사례:

  자원 관리:
    - 수동 (try/catch/finally) →
    - try-with-resources →
    - @AutoClosable

  의존성 주입:
    - new 직접 →
    - 팩토리 →
    - DI 컨테이너 (Spring)

  매핑:
    - JDBC ResultSet →
    - RowMapper (람다) →
    - JPA 어노테이션

→ 모두 같은 정신 (점진적 자동화)

8.4 실무의 가치

실무의 가치:

  코드 품질 ↑:
    - 비즈니스 집중
    - 가독성 ↑
    - 유지보수 ↑

  생산성 ↑:
    - 빠른 개발
    - 안전한 코드
    - 적은 인력 운영

  운영 안전 ↑:
    - 함정 자동 회피
    - 일관 패턴

→ "현대 자바 백엔드의 표준"

8.5 박승제의 가치

박승제의 가치

ILIC 의 박승제:
  - 102 테이블 + 1020 메서드
  - 풀스택 (혼자 + 1 명)
  - 어떻게 운영?

  @Transactional 의 가치:
    - 1020 어노테이션
    - 비즈니스만 작성
    - 함정 자동 회피
    - 코드 리뷰 효율

  Phase 7 학습 후:
    - 동작 원리 이해
    - 함정 회피
    - 트러블슈팅 능력
    - 면접 우위

→ Spring Boot 개발자의 핵심

8.6 자기 점검 답변

진화의 의미는?

:
1. 진화:

  • 수동 → 자동화
  1. 자바 정신:

    • 추상화 + 표준
  2. 다른 사례:

    • 자원 / DI / 매핑
  3. 가치:

    • 코드 / 생산성 / 안전

9️⃣ Phase 6 완주 + Phase 7 ★★★ 예고

9.1 Phase 6 학습 종합

🎯 Phase 6 — PlatformTransactionManager

Unit 6.1 — 인터페이스 추상화:
  - PlatformTransactionManager
  - 3 메서드
  - 5주차 DIP + 6주차 DataSource 정신

Unit 6.2 — 3가지 구현체:
  - DataSourceTM / HibernateTM / JpaTM
  - 선택 기준
  - 혼용 (JPA + JdbcTemplate)

Unit 6.3 — 사용 전후 비교 ← 여기:
  - 4 단계 진화
  - Before / After 1 / 2 / 3
  - Phase 6 완주

9.2 핵심 메시지

Phase 6 핵심 메시지:

  "PlatformTransactionManager 는 Spring 의 트랜잭션 추상화 인터페이스로
   5주차 DIP / 6주차 DataSource 와 같은 사상이며,
   인터페이스 (PlatformTM) + 구현체 (DataSource/Hibernate/Jpa TM)
   + 활용 (직접 / TransactionTemplate / @Transactional) 의
   완벽한 추상화 흐름이 자바 백엔드 트랜잭션의 진화다."

9.3 Phase 7 예고 (★★★)

✨ Phase 7 — @Transactional (3 Unit, 모두 ★ 깊이)

  Unit 7.1 — 프록시 패턴 ★:
    - 5주차 프록시 패턴 활용
    - JDK 동적 프록시 / CGLIB
    - Spring AOP 의 기반

  Unit 7.2 — @Transactional 동작 원리 ★★★:
    - 어노테이션 → 프록시 → 트랜잭션
    - Bean Post Processor
    - 진짜 메서드 호출 흐름
    - 면접 정점

  Unit 7.3 — @Transactional 5가지 함정 ★:
    - private 메서드
    - self-invocation
    - checked exception
    - propagation
    - readOnly

→ 자바 백엔드의 정점
→ 7주차 종합 졸업 시험 24문항

9.4 Phase 7 의 가치

Phase 7 의 가치:

  1. 면접 단골:
     - "@Transactional 동작 원리?"
     - "프록시 패턴?"
     - "5가지 함정?"

  2. 실무 핵심:
     - 매일 사용
     - 함정 회피 필수
     - 트러블슈팅

  3. 깊은 이해:
     - 5+6+7주차 응축
     - 자바 백엔드 정수

  4. 7주차 정점:
     - 마지막 ★★★ Phase
     - 졸업 시험 24문항

9.5 7주차 진행

🗂️ Part A — 데이터 모델링과 ORM (완주)
  ✅ Phase 1-4 (16)

🔄 Part B — 트랜잭션 추상화의 진화
  ✅ Phase 5 (2)
  ✅ Phase 6 (3) ← 완주!
  ⏭ Phase 7 (3) — 모두 ★ 깊이

총: 21/24 Unit (88%, Phase 6 완주!)

9.6 ILIC 의 다음 단계

ILIC 의 다음 단계 (학습)

Phase 7 학습 후:
  - @Transactional 동작 원리 이해
  - 프록시 / AOP 디버깅 능력
  - 5가지 함정 회피
  - propagation 활용

  ILIC 의 1020 메서드:
    - 더 깊은 이해
    - 안전한 운영
    - 효율적 코드 리뷰

  박승제 의 면접 우위:
    - 시니어 개발자 시험
    - 깊은 답변

9.7 면접 단골 질문 매핑

Q핵심 답변
4 단계 진화?Before/After1/2/3
Before?수동 (15 줄)
PlatformTM 직접?12 줄, 인터페이스
TransactionTemplate?람다 (5 줄)
@Transactional?1 줄 (AOP)
SoC 점진적?After3 완벽
5주차 패턴?DI/DIP/OCP/템플릿+전략/프록시
6주차 정신?DataSource 동일
코드 절약?ILIC 15,000+
Phase 7?★★★ 정점

9.8 자기 점검 체크리스트

4 단계

  • Before/After1/2/3

Before

  • 수동

After 1

  • PlatformTM 직접

After 2

  • TransactionTemplate

After 3

  • @Transactional

비교

  • 코드 / SoC / 안전

5+6주차 응축

  • 정신

진화

  • 의미

Phase 7

  • ★★★

9.9 추가 심화 질문

Q1: TransactionTemplate 의 단점?

답:

  • 람다 안에서 예외 처리 미묘
  • 메서드 시그너처 노이즈
  • 메서드 일부만 트랜잭션 시 유용
  • 일반은 @Transactional

Q2: @Transactional vs TransactionTemplate?

답:

  • @Transactional: 메서드 전체
  • TransactionTemplate: 일부 코드 블록
  • 90% @Transactional / 10% TransactionTemplate

Q3: Selective rollback?

답:

  • @Transactional(rollbackFor = {})
  • 또는 status.setRollbackOnly()
  • 또는 throw 어떤 예외?

Q4: Spring Boot 의 자동 트랜잭션?

답:

  • Spring Data JPA Repository 의 기본 메서드 = 자동 @Transactional
  • save / delete 등은 자동 트랜잭션
  • 단 readOnly 가 readOnly = true (조회)

Q5: 어노테이션 vs XML 트랜잭션?

답:

  • 어노테이션 = 표준 (현대)
  • XML = 옛 스타일 (Spring 1-3)
  • AOP 설정도 가능 (서비스 패키지 전체 @Transactional 등)

🎯 핵심 요약 — 3줄 정리

1. 4 단계 진화

  • Before (수동, 15 줄) → After 1 (PlatformTM 직접, 12 줄)
  • → After 2 (TransactionTemplate 람다, 5 줄) → After 3 (@Transactional, 1 줄)
  • 코드 18 → 3 줄 (83% 절약), ILIC 의 15,000 줄 보일러플레이트 제거

2. 5+6주차 응축

  • 5주차: DI / DIP / OCP / 템플릿+전략 / 프록시 패턴
  • 6주차: DataSource 추상화 + JdbcTemplate 의 정신
  • 7주차 Part B: 모든 정신의 결정체 (PlatformTM → @Transactional)

3. Phase 7 ★★★ 정점

  • Unit 7.1: 프록시 패턴 ★
  • Unit 7.2: @Transactional 동작 원리 ★★★ (면접 정점)
  • Unit 7.3: 5가지 함정 ★
  • 7주차 종합 졸업 시험 24문항 포함

🏆 Phase 6 완주 — PlatformTransactionManager

🎯 Phase 6 — PlatformTransactionManager
  ✅ Unit 6.1 인터페이스 추상화
  ✅ Unit 6.2 3가지 구현체 (DataSourceTM/HibernateTM/JpaTM)
  ✅ Unit 6.3 사용 전후 비교 ← 여기, Phase 6 완주

→ Spring 의 트랜잭션 추상화 완전 정복
→ 5주차 + 6주차 정신 응축
→ Phase 7 (@Transactional ★★★) 의 기반

📚 다음으로...

Phase 7 — @Transactional (3 Unit, 모두 ★ 깊이)

✨ Phase 7 — @Transactional (마지막)
  Unit 7.1 — 프록시 패턴 ★
  Unit 7.2 — @Transactional 동작 원리 ★★★
  Unit 7.3 — @Transactional 5가지 함정 ★
+ 종합 졸업 시험 24문항

Phase 7 의 가치:

  • 자바 백엔드의 정점
  • 면접 단골 ★★★
  • @Transactional 완벽 이해
  • 5+6+7주차 응축

7주차 누적 진행

🗂️ Part A — 데이터 모델링과 ORM (완주)
  ✅ Phase 1-4 (16)

🔄 Part B — 트랜잭션 추상화의 진화
  ✅ Phase 5 (2)
  ✅ Phase 6 (3) ← 완주
  ⏭ Phase 7 (3) — 모두 ★ 깊이

총: 21/24 Unit (88%, Phase 6 완주!)

🏆 Phase 6 완주 — 점진적 추상화의 흐름

profile
Software Developer

0개의 댓글