7주차 Unit 6.2 — 3가지 구현체 (DataSourceTM/HibernateTM/JpaTM)

Psj·2026년 6월 5일

F-lab

목록 보기
232/239

Unit 6.2 — 3가지 구현체 (DataSourceTM/HibernateTM/JpaTM)

F-LAB JAVA · 7주차 · Phase 6 · PlatformTransactionManager


📌 학습 목표

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

  • 3가지 구현체 개요 는?
  • DataSourceTransactionManager 는?
  • HibernateTransactionManager 는?
  • JpaTransactionManager 는?
  • 각 구현체의 내부 동작 차이는?
  • 선택 기준 은?
  • JPA + JdbcTemplate 혼용 환경 의 TM 선택은?
  • Spring Boot 자동 구성 은?
  • ILIC 의 선택 은?

🎯 핵심 한 문장

PlatformTransactionManager 의 3가지 구현체 — DataSourceTransactionManager (JDBC / JdbcTemplate, DataSource 받아 Connection.setAutoCommit(false) 호출), HibernateTransactionManager (Hibernate 직접, SessionFactory 받음, 옛 스타일), JpaTransactionManager (JPA / Spring Data JPA, EntityManagerFactory 받음) — 사용 기술에 따라 선택되며 JPA + JdbcTemplate 혼용 환경에선 JpaTransactionManager 가 DataSource 도 인식해 단일 트랜잭션 보장이 가능하고 Spring Boot 는 의존성에 따라 자동 선택한다.
Spring 의 PlatformTransactionManager3가지 핵심 구현체 가 있으며 사용 기술에 따라 선택한다.
(1) DataSourceTransactionManager — 가장 기본적, JDBC / JdbcTemplate / MyBatis 사용 시, DataSource 빈을 받아 내부적으로 Connection.setAutoCommit(false)commit()rollback() 을 호출.
(2) HibernateTransactionManagerHibernate 를 JPA 없이 직접 사용 시 (드묾, 옛 스타일), SessionFactory 빈을 받아 Session.beginTransaction() 호출.
(3) JpaTransactionManagerJPA / Spring Data JPA 사용 시 (현대 표준), EntityManagerFactory 빈을 받아 EntityManager.getTransaction().begin() 호출.
선택 기준 — JdbcTemplate 만 = DataSourceTM, Hibernate 직접 = HibernateTM, JPA = JpaTM 인데 — JPA + JdbcTemplate 혼용 시 JpaTransactionManager 사용 (JPA 의 EntityManagerFactory 가 같은 DataSource 를 공유하므로 단일 Connection / 단일 트랜잭션 가능, JdbcTemplate 도 같은 Connection 으로 동작 = 두 도구가 같은 트랜잭션 공유).
Spring Boot 는 — spring-boot-starter-data-jpa 의존성 시 JpaTransactionManager, spring-boot-starter-jdbc 만 시 DataSourceTransactionManager 자동 등록.

비유 — 자동차 변속기 3 종류

3가지 구현체 = 3 변속기:

상황:
  - 같은 핸들 (PlatformTransactionManager)
  - 다른 변속기 (구현체)
  - 운전법 같음 (인터페이스)

[1] DataSourceTM (수동 변속기, 가장 단순):
  - JDBC 직접 (Connection)
  - JdbcTemplate / MyBatis 가 사용
  - 기본 / 가벼움

[2] HibernateTM (자동 변속기 옛 모델, 드묾):
  - Hibernate 직접 (SessionFactory)
  - JPA 안 쓸 때
  - 거의 안 씀

[3] JpaTM (자동 변속기 신모델, 표준):
  - JPA / Spring Data JPA
  - EntityManagerFactory
  - 현대 표준

선택:
  - 사용 기술 보고
  - Spring Boot 자동
  - 코드 변경 X

혼용 (JPA + JdbcTemplate):
  - JpaTM 으로 통합
  - 같은 DataSource 공유
  - 같은 트랜잭션

ILIC:
  - JPA 주력 → JpaTransactionManager
  - JdbcTemplate 보조 → 같은 TM 으로

→ 3 구현체, 인터페이스 같음, 사용 기술 따라 선택, 혼용 시 JpaTM.


🧭 9개 섹션 로드맵

1. 3가지 구현체 개요
2. DataSourceTransactionManager
3. HibernateTransactionManager
4. JpaTransactionManager
5. 각 구현체의 내부 동작
6. 선택 기준
7. JPA + JdbcTemplate 혼용
8. Spring Boot 자동 구성
9. ILIC 의 선택 + Phase 6.3 예고

1️⃣ 3가지 구현체 개요

1.1 3가지 구현체

구현체사용 기술받는 빈인기
DataSourceTransactionManagerJDBC, JdbcTemplate, MyBatisDataSource★★
HibernateTransactionManagerHibernate 직접 (JPA 없이)SessionFactory★ (드묾)
JpaTransactionManagerJPA, Spring Data JPAEntityManagerFactory★★★ (표준)

1.2 모두 같은 인터페이스

모두 같은 인터페이스:

  3 구현체 모두:
    - PlatformTransactionManager 구현
    - 3 메서드 (getTransaction/commit/rollback)

  애플리케이션:
    - 인터페이스만 의존
    - 구현체 모름

→ 5주차 DIP / OCP

1.3 내부 동작은 다름

내부 동작 다름:

  DataSourceTM:
    - Connection.setAutoCommit(false)
    - Connection.commit / rollback

  HibernateTM:
    - Session.beginTransaction()
    - Transaction.commit / rollback

  JpaTM:
    - EntityManager.getTransaction().begin()
    - EntityTransaction.commit / rollback

→ 내부는 다르지만 외부는 같음

1.4 ILIC 의 맥락

// ILIC 의 구현체 (Spring Boot 자동)

// 사용 빈 (Spring Boot 가 자동 생성)
@Bean
public PlatformTransactionManager transactionManager(
        EntityManagerFactory emf) {
    return new JpaTransactionManager(emf);
}

// → ILIC = JPA 사용
// → JpaTransactionManager 자동
// → 모든 @Transactional 이 이 TM 사용
class PlatformTransactionManager {}
class JpaTransactionManager extends PlatformTransactionManager {
    JpaTransactionManager(EntityManagerFactory emf) {}
}
class EntityManagerFactory {}
@interface Bean {}
EntityManagerFactory emf;

1.5 자기 점검 답변

3가지 구현체 개요는?

:
1. 3가지:

  • DataSourceTM / HibernateTM / JpaTM
  1. 인터페이스:

    • 모두 같음
  2. 내부:

    • 다름
  3. 표준:

    • JpaTM

2️⃣ DataSourceTransactionManager

2.1 DataSourceTransactionManager

DataSourceTransactionManager:

  JDBC 기반 트랜잭션 관리:
    - DataSource 받음
    - Connection 사용
    - 가장 기본

  사용 케이스:
    - JdbcTemplate (6주차)
    - MyBatis
    - JDBC 직접

2.2 빈 등록

@Configuration
public class TransactionConfig {
    
    @Bean
    public DataSource dataSource() {
        return new HikariDataSource(/* config */);
    }
    
    @Bean
    public PlatformTransactionManager transactionManager(
            DataSource dataSource) {
        return new DataSourceTransactionManager(dataSource);
    }
}
class HikariDataSource implements DataSource {}
interface DataSource {}
class DataSourceTransactionManager implements PlatformTransactionManager {
    DataSourceTransactionManager(DataSource ds) {}
}
interface PlatformTransactionManager {}
@interface Configuration {}
@interface Bean {}

2.3 내부 동작

내부 동작 (개념):

  getTransaction:
    1. dataSource.getConnection() (풀에서)
    2. conn.setAutoCommit(false) ← 트랜잭션 시작
    3. ThreadLocal 에 Connection 저장
    4. TransactionStatus 반환

  commit:
    1. conn.commit()
    2. conn.setAutoCommit(true)
    3. ThreadLocal 정리
    4. conn.close() (풀 반환)

  rollback:
    1. conn.rollback()
    2. conn.setAutoCommit(true)
    3. ThreadLocal 정리
    4. conn.close()

2.4 ThreadLocal 의 역할

ThreadLocal:

  Spring 의 트랜잭션 동기화:
    - 같은 트랜잭션 = 같은 쓰레드
    - 같은 쓰레드 = 같은 Connection
    - ThreadLocal 로 저장

  효과:
    - JdbcTemplate 호출 시
    - 같은 Connection 사용
    - 단일 트랜잭션

→ TransactionSynchronizationManager

2.5 JdbcTemplate 과 연동

// JdbcTemplate 자동 연동
@Service
public class ShipmentDao {
    @Autowired JdbcTemplate jdbcTemplate;
    
    public void update(Shipment s) {
        // jdbcTemplate 가 자동으로:
        // 1. 현재 트랜잭션 Connection 확인 (ThreadLocal)
        // 2. 있으면 그 Connection 사용
        // 3. 없으면 새 Connection
        
        jdbcTemplate.update("UPDATE shipments SET status = ?", s.getStatus());
    }
}

@Service
public class ShipmentService {
    @Autowired ShipmentDao dao;
    
    @Transactional   // DataSourceTransactionManager 가 처리
    public void process(Long id) {
        dao.update(s1);   // 같은 Connection
        dao.update(s2);   // 같은 Connection
        // 단일 트랜잭션
    }
}
class Shipment { String getStatus() { return null; } }
class JdbcTemplate { void update(String s, Object... a) {} }
JdbcTemplate jdbcTemplate;
ShipmentDao dao;
Shipment s1, s2;
@interface Service {}
@interface Autowired {}
@interface Transactional {}

2.6 ILIC 의 맥락 (가정)

ILIC 가 JdbcTemplate 만 사용한다면 (가정)

설정:
  @Bean DataSourceTransactionManager

사용:
  @Transactional
  public void process() {
      jdbcTemplate.update(...);
      jdbcTemplate.query(...);
      // 같은 Connection / 단일 트랜잭션
  }

  Spring Boot:
    - spring-boot-starter-jdbc
    - 자동 DataSourceTransactionManager

→ 단순 / 가벼움
→ 하지만 ILIC = JPA 주력

2.7 자기 점검 답변

DataSourceTransactionManager 는?

:
1. DataSourceTM:

  • JDBC 기반
  1. 사용:

    • JdbcTemplate / MyBatis
  2. 내부:

    • Connection.setAutoCommit
  3. ThreadLocal:

    • 트랜잭션 동기화

3️⃣ HibernateTransactionManager

3.1 HibernateTransactionManager

HibernateTransactionManager:

  Hibernate 직접 사용 시 (JPA 없이):
    - SessionFactory 받음
    - Session 사용

  현재는 드묾:
    - JPA 가 표준
    - Hibernate 직접 케이스 적음

3.2 빈 등록

@Configuration
public class HibernateConfig {
    
    @Bean
    public SessionFactory sessionFactory() {
        // Hibernate 직접 설정
        Configuration cfg = new Configuration();
        cfg.configure("hibernate.cfg.xml");
        return cfg.buildSessionFactory();
    }
    
    @Bean
    public PlatformTransactionManager transactionManager(
            SessionFactory sessionFactory) {
        return new HibernateTransactionManager(sessionFactory);
    }
}
class SessionFactory {}
class Configuration {
    Configuration configure(String s) { return this; }
    SessionFactory buildSessionFactory() { return null; }
}
class HibernateTransactionManager implements PlatformTransactionManager {
    HibernateTransactionManager(SessionFactory sf) {}
}
interface PlatformTransactionManager {}
@interface Configuration {}
@interface Bean {}

3.3 Hibernate 직접

// Hibernate 직접 사용 (드묾)
@Repository
public class ShipmentDao {
    @Autowired SessionFactory sessionFactory;
    
    public Shipment findById(Long id) {
        Session session = sessionFactory.getCurrentSession();
        return session.get(Shipment.class, id);
    }
    
    public void save(Shipment s) {
        Session session = sessionFactory.getCurrentSession();
        session.save(s);
    }
}

// 사용
@Service
public class ShipmentService {
    @Autowired ShipmentDao dao;
    
    @Transactional   // HibernateTransactionManager
    public void process(Long id) {
        Shipment s = dao.findById(id);
        s.markAsShipped();
        dao.save(s);
    }
}
class Shipment { void markAsShipped() {} }
class SessionFactory { Session getCurrentSession() { return null; } }
class Session { <T> T get(Class<T> c, Object id) { return null; } void save(Object o) {} }
SessionFactory sessionFactory;
ShipmentDao dao;
@interface Repository {}
@interface Service {}
@interface Autowired {}
@interface Transactional {}

3.4 왜 드묾?

왜 드묾?:

  Hibernate 직접:
    - JPA 보다 강력 (Hibernate 고유 기능)
    - 하지만 표준 X

  JPA + Hibernate:
    - JPA 표준 사용
    - 내부적으로 Hibernate (구현체)
    - 표준 + 강력

→ 거의 모두 JPA 사용
→ HibernateTransactionManager 거의 X

3.5 옛 시스템

옛 시스템 케이스:

  - 2000년대 초중반 시스템
  - JPA 표준 이전 시스템
  - 마이그레이션 어려운 레거시

→ 현재 신규는 JPA

3.6 내부 동작

내부 동작 (개념):

  getTransaction:
    1. sessionFactory.openSession()
    2. session.beginTransaction()
    3. ThreadLocal 저장
    4. TransactionStatus 반환

  commit:
    1. session.getTransaction().commit()
    2. session.close()
    3. ThreadLocal 정리

  rollback:
    1. session.getTransaction().rollback()
    2. session.close()

3.7 ILIC 의 맥락

ILIC = HibernateTransactionManager X

ILIC = JPA + Hibernate (JPA 모드):
  - JpaTransactionManager 사용
  - HibernateTransactionManager 사용 X
  - 표준 JPA 인터페이스

  Hibernate 고유 기능 (드물게):
    - @DynamicUpdate
    - @BatchSize
    - HQL (HibernateTransactionManager 없이도 OK)

→ JpaTransactionManager 만으로 충분

3.8 자기 점검 답변

HibernateTransactionManager 는?

:
1. HibernateTM:

  • Hibernate 직접
  1. SessionFactory:

    • 받음
  2. 현재:

    • 드묾
  3. 이유:

    • JPA 표준이 대체

4️⃣ JpaTransactionManager

4.1 JpaTransactionManager

JpaTransactionManager:

  JPA / Spring Data JPA:
    - EntityManagerFactory 받음
    - EntityManager 사용

  현대 표준:
    - 99% 사용
    - Spring Boot 자동

4.2 빈 등록

@Configuration
public class JpaConfig {
    
    @Bean
    public EntityManagerFactory entityManagerFactory() {
        // JPA 설정 (보통 Spring Boot 자동)
    return null;
    }
    
    @Bean
    public PlatformTransactionManager transactionManager(
            EntityManagerFactory emf) {
        return new JpaTransactionManager(emf);
    }
}
class EntityManagerFactory {}
class JpaTransactionManager implements PlatformTransactionManager {
    JpaTransactionManager(EntityManagerFactory emf) {}
}
interface PlatformTransactionManager {}
@interface Configuration {}
@interface Bean {}

4.3 JPA 사용

// JPA Repository (Spring Data JPA)
public interface ShipmentRepository extends JpaRepository<Shipment, Long> {
    // 자동 구현
}

// 서비스
@Service
public class ShipmentService {
    @Autowired ShipmentRepository repo;
    
    @Transactional   // JpaTransactionManager
    public void process(Long id) {
        Shipment s = repo.findById(id).orElseThrow();
        s.markAsShipped();
        // 트랜잭션 commit 시 Dirty Checking → UPDATE
    }
}
class Shipment { void markAsShipped() {} }
interface JpaRepository<T, ID> { java.util.Optional<T> findById(ID id); }
interface ShipmentRepository extends JpaRepository<Shipment, Long> {}
ShipmentRepository repo;
@interface Service {}
@interface Autowired {}
@interface Transactional {}

4.4 내부 동작

내부 동작 (개념):

  getTransaction:
    1. emf.createEntityManager()
    2. em.getTransaction().begin()
    3. EntityManager 를 ThreadLocal 저장
    4. TransactionStatus 반환

  commit:
    1. em.flush() (변경 사항 DB 반영)
    2. em.getTransaction().commit()
    3. em.close()
    4. ThreadLocal 정리

  rollback:
    1. em.getTransaction().rollback()
    2. em.close()
    3. ThreadLocal 정리

4.5 영속성 컨텍스트와 트랜잭션

영속성 컨텍스트 ↔ 트랜잭션:

  JPA 의 영속성 컨텍스트:
    - 트랜잭션 시작 시 생성
    - 트랜잭션 commit 시 flush
    - 트랜잭션 종료 시 close

  Dirty Checking:
    - 영속성 컨텍스트의 객체 변경 감지
    - flush 시 UPDATE 자동
    - JPA 의 강력한 기능

→ JpaTransactionManager 가 모두 처리

4.6 OSIV (Open Session In View)

OSIV (Open Session In View):

  - Spring Boot 기본 ON
  - 영속성 컨텍스트를 View 까지 유지
  - Controller 에서 Lazy Loading 가능

  단점:
    - Connection 점유 길어짐
    - 풀 부하

  운영 권장:
    spring.jpa.open-in-view: false

4.7 Hibernate (JPA 모드)

Hibernate (JPA 모드):

  JpaTransactionManager 가 EntityManagerFactory 받음:
    - 내부 구현은 Hibernate
    - 하지만 JPA 표준 인터페이스로 동작
    - Hibernate 고유 기능도 활용 가능

→ 표준 + 강력

4.8 ILIC 의 맥락

# ILIC application.yml
spring:
  datasource:
    url: jdbc:mysql://...
    username: ...
    password: ...
  jpa:
    hibernate:
      ddl-auto: validate
    properties:
      hibernate:
        format_sql: true
        default_batch_fetch_size: 100
    open-in-view: false   # 운영 권장
// ILIC 의 표준 (자동)
// Spring Boot 가 자동 등록:
// - HikariDataSource (DataSource)
// - EntityManagerFactory (JPA, Hibernate 구현)
// - JpaTransactionManager (TM)

@Service
public class ShipmentService {
    @Autowired ShipmentRepository repo;
    
    @Transactional   // JpaTransactionManager 가 처리
    public void process(Long id) {
        Shipment s = repo.findById(id).orElseThrow();
        s.markAsShipped();
        // Dirty Checking → UPDATE 자동
    }
}

// → 102 테이블 / 1020 메서드 모두 같은 패턴
class Shipment { void markAsShipped() {} }
ShipmentRepository repo;
interface ShipmentRepository { java.util.Optional<Shipment> findById(Long id); }
@interface Service {}
@interface Autowired {}
@interface Transactional {}

4.9 자기 점검 답변

JpaTransactionManager 는?

:
1. JpaTM:

  • JPA / Spring Data JPA
  1. EntityManagerFactory:

    • 받음
  2. 현대 표준:

    • 99%
  3. 영속성 컨텍스트:

    • 트랜잭션과 함께

5️⃣ 각 구현체의 내부 동작

5.1 비교 표

항목DataSourceTMHibernateTMJpaTM
받는 빈DataSourceSessionFactoryEntityManagerFactory
트랜잭션 객체ConnectionSessionEntityManager
시작 메서드setAutoCommit(false)beginTransaction()getTransaction().begin()
커밋conn.commit()tx.commit()tx.commit() (+ flush)
롤백conn.rollback()tx.rollback()tx.rollback()
종료conn.close()session.close()em.close()
ThreadLocalConnectionSessionEntityManager

5.2 ThreadLocal 의 키

ThreadLocal 의 키:

  DataSourceTM:
    - DataSource → Connection 매핑

  JpaTM:
    - EntityManagerFactory → EntityManager 매핑

  TransactionSynchronizationManager:
    - Spring 의 트랜잭션 동기화 클래스
    - getResource(key) / bindResource(key, value)

5.3 도구와 자동 연동

도구와 자동 연동:

  JdbcTemplate:
    - DataSource 받음
    - DataSourceUtils.getConnection(dataSource)
    - ThreadLocal 에서 Connection 가져옴 (있으면)
    - 또는 새 Connection
    
  Spring Data JPA:
    - EntityManagerFactory 받음
    - 같은 방식

→ 자동 동기화

5.4 내부 코드 (간략)

// DataSourceTransactionManager (간략)
public class DataSourceTransactionManager 
    extends AbstractPlatformTransactionManager {
    
    private DataSource dataSource;
    
    @Override
    protected Object doGetTransaction() {
        // ThreadLocal 에서 ConnectionHolder 가져옴
        ConnectionHolder holder = (ConnectionHolder)
            TransactionSynchronizationManager.getResource(dataSource);
        return new DataSourceTransactionObject(holder);
    }
    
    @Override
    protected void doBegin(Object transaction, TransactionDefinition definition) {
        Connection conn = dataSource.getConnection();
        conn.setAutoCommit(false);   // ★ 핵심
        
        // ThreadLocal 바인딩
        TransactionSynchronizationManager.bindResource(
            dataSource, new ConnectionHolder(conn));
    }
    
    @Override
    protected void doCommit(DefaultTransactionStatus status) {
        ConnectionHolder holder = (ConnectionHolder) status.getTransaction();
        holder.getConnection().commit();   // ★ 핵심
    }
    
    @Override
    protected void doRollback(DefaultTransactionStatus status) {
        ConnectionHolder holder = (ConnectionHolder) status.getTransaction();
        holder.getConnection().rollback();   // ★ 핵심
    }
}
class AbstractPlatformTransactionManager {}
class DataSourceTransactionObject { DataSourceTransactionObject(ConnectionHolder h) {} }
class ConnectionHolder {
    ConnectionHolder(Connection c) {}
    Connection getConnection() { return null; }
}
class TransactionSynchronizationManager {
    static Object getResource(Object key) { return null; }
    static void bindResource(Object key, Object value) {}
}
class TransactionDefinition {}
class DefaultTransactionStatus { Object getTransaction() { return null; } }
DataSource dataSource;
interface DataSource { Connection getConnection() throws SQLException; }

5.5 JpaTransactionManager 의 차이

// JpaTransactionManager (간략)
public class JpaTransactionManager 
    extends AbstractPlatformTransactionManager {
    
    private EntityManagerFactory entityManagerFactory;
    
    @Override
    protected void doBegin(Object transaction, TransactionDefinition definition) {
        EntityManager em = entityManagerFactory.createEntityManager();
        em.getTransaction().begin();   // ★ JPA 방식
        
        // ThreadLocal 에 바인딩
        TransactionSynchronizationManager.bindResource(
            entityManagerFactory, new EntityManagerHolder(em));
        
        // DataSource 도 인식 (혼용 가능!)
        // 같은 Connection 공유
    }
    
    @Override
    protected void doCommit(DefaultTransactionStatus status) {
        EntityManagerHolder holder = (EntityManagerHolder) status.getTransaction();
        EntityManager em = holder.getEntityManager();
        em.flush();                              // ★ 변경 사항 DB 반영
        em.getTransaction().commit();             // ★ 커밋
    }
}
class EntityManagerHolder {
    EntityManagerHolder(EntityManager em) {}
    EntityManager getEntityManager() { return null; }
}
class EntityManager {
    EntityTransaction getTransaction() { return null; }
    void flush() {}
}
class EntityTransaction { void begin() {} void commit() {} }
class AbstractPlatformTransactionManager {}
class TransactionDefinition {}
class DefaultTransactionStatus { Object getTransaction() { return null; } }
class TransactionSynchronizationManager {
    static void bindResource(Object key, Object value) {}
}
class EntityManagerFactory { EntityManager createEntityManager() { return null; } }
EntityManagerFactory entityManagerFactory;

5.6 ILIC 의 맥락

ILIC = JpaTransactionManager

ILIC 의 동작:
  1. @Transactional 호출
  2. JpaTransactionManager.doBegin()
     - EntityManager 생성
     - em.getTransaction().begin()
     - ThreadLocal 에 EntityManagerHolder
     - + DataSource 에 ConnectionHolder (혼용용)
  3. 비즈니스 로직 (Repository / JdbcTemplate)
     - 모두 같은 Connection 사용
  4. JpaTransactionManager.doCommit()
     - em.flush() (Dirty Checking)
     - em.getTransaction().commit()
     - em.close()

→ 모든 도구가 같은 트랜잭션

5.7 자기 점검 답변

각 구현체의 내부 동작 차이는?

:
1. DataSourceTM:

  • Connection.setAutoCommit
  1. HibernateTM:

    • Session.beginTransaction
  2. JpaTM:

    • EntityManager.getTransaction().begin
  3. 공통:

    • ThreadLocal + 인터페이스

6️⃣ 선택 기준

6.1 선택 매트릭스

사용 기술선택
JdbcTemplate / MyBatis 만DataSourceTransactionManager
Hibernate 직접 (JPA 없이)HibernateTransactionManager (드묾)
JPA / Spring Data JPAJpaTransactionManager
JPA + JdbcTemplate 혼용JpaTransactionManager (다음 섹션)
Hibernate (JPA 모드)JpaTransactionManager

6.2 의사 결정 흐름

의사 결정:

  Q: JPA 사용?
  Y → JpaTransactionManager
  N → Q: Hibernate 직접?
     Y → HibernateTransactionManager (드묾)
     N → Q: JdbcTemplate 만?
        Y → DataSourceTransactionManager
        N → ... (특수)

6.3 실무 비율

실무 비율:

  JpaTransactionManager: 80%+
    - JPA / Spring Data JPA 사용
    - 현대 표준

  DataSourceTransactionManager: 10-15%
    - JdbcTemplate / MyBatis 만
    - 통계 / 분석 시스템

  HibernateTransactionManager: <5%
    - 옛 시스템
    - 거의 X

6.4 변경 시

변경 시:

  JPA → JdbcTemplate 만:
    - JpaTM → DataSourceTM
    - 빈 변경
    - 코드는?
      - @Transactional 그대로
      - Repository 만 변경

  애플리케이션 코드:
    - 인터페이스 의존
    - 최소 변경

6.5 ILIC 의 선택

ILIC 의 선택:

  ILIC = Spring Boot + JPA + Spring Data JPA
  → JpaTransactionManager 자동 (Spring Boot)

  추가로:
    - JdbcTemplate 도 사용 (복잡 통계)
    - 혼용 환경 → 다음 섹션

6.6 자기 점검 답변

선택 기준은?

:
1. JPA:

  • JpaTM
  1. JdbcTemplate:

    • DataSourceTM
  2. 혼용:

    • JpaTM
  3. 자동:

    • Spring Boot

7️⃣ JPA + JdbcTemplate 혼용

7.1 혼용 시나리오

혼용 시나리오:

  대부분 JPA + 일부 JdbcTemplate:
    - JPA: 단순 CRUD
    - JdbcTemplate: 복잡 통계

  같은 트랜잭션 안에서:
    - JPA save (Dirty Checking)
    - JdbcTemplate 통계 쿼리
    - 모두 같은 트랜잭션?

7.2 JpaTM 의 마법

JpaTM 의 마법:

  JpaTransactionManager 는:
    - EntityManagerFactory 받지만
    - 내부적으로 DataSource 도 인식
    - 같은 Connection 사용

  결과:
    - JPA 도 같은 Connection
    - JdbcTemplate 도 같은 Connection
    - 단일 트랜잭션 보장

7.3 실무 예시

@Service
public class ShipmentService {
    @Autowired ShipmentRepository repo;       // JPA
    @Autowired JdbcTemplate jdbcTemplate;      // JDBC
    
    @Transactional
    public void process(Long id) {
        // 1. JPA 로 조회
        Shipment s = repo.findById(id).orElseThrow();
        s.markAsShipped();
        // → Dirty Checking 예약
        
        // 2. JdbcTemplate 로 복잡 통계 업데이트
        jdbcTemplate.update("""
            UPDATE shipment_stats 
            SET shipped_count = shipped_count + 1
            WHERE customer_id = ?
            """, s.getCustomerId());
        
        // 3. 트랜잭션 commit:
        //    - JPA flush (UPDATE shipments)
        //    - + 위 UPDATE shipment_stats
        //    - 모두 같은 Connection
        //    - 단일 트랜잭션
        //    - 원자적 (모두 성공 / 모두 실패)
    }
}
class Shipment { void markAsShipped() {} Long getCustomerId() { return null; } }
ShipmentRepository repo;
interface ShipmentRepository { java.util.Optional<Shipment> findById(Long id); }
JdbcTemplate jdbcTemplate;
class JdbcTemplate { void update(String s, Object... a) {} }
@interface Service {}
@interface Autowired {}
@interface Transactional {}

7.4 ThreadLocal 의 공유

ThreadLocal 의 공유:

  JpaTM doBegin():
    1. EntityManager 생성
    2. em.getTransaction().begin()
    3. ThreadLocal 에:
       - EntityManagerHolder (JPA 키)
       - ConnectionHolder (DataSource 키, 같은 Connection)
    4. JdbcTemplate 호출 시 → 같은 Connection
    5. JPA 호출 시 → 같은 Connection

→ 통합 트랜잭션

7.5 주의 사항

주의 사항:

  1. flush 시점:
     - JPA 의 변경 사항이 DB 에 언제 반영?
     - 보통 commit 직전 자동 flush
     - JdbcTemplate 쿼리 전에 flush 안 됨!
     - 명시적 em.flush() 필요할 수 있음

  2. 캐시 일관성:
     - JPA 1차 캐시 vs DB
     - JdbcTemplate 직접 DB 수정 시
     - JPA 캐시는 모름
     - em.refresh() 또는 em.clear() 필요

→ 혼용 시 주의

7.6 명시적 flush 예시

@Transactional
public void process(Long id) {
    Shipment s = repo.findById(id).orElseThrow();
    s.markAsShipped();
    
    // 명시적 flush
    entityManager.flush();   // ← Dirty Checking → UPDATE SQL 실행
    
    // 이제 JdbcTemplate 쿼리에서
    // 최신 status 반영됨
    jdbcTemplate.query(...);
}
class Shipment { void markAsShipped() {} }
ShipmentRepository repo;
interface ShipmentRepository { java.util.Optional<Shipment> findById(Long id); }
class EntityManager { void flush() {} }
EntityManager entityManager;
JdbcTemplate jdbcTemplate;
class JdbcTemplate { void query(Object... a) {} }
@interface Transactional {}

7.7 ILIC 의 맥락

// ILIC 의 혼용 (실제 패턴)

@Service
public class ShipmentReportService {
    @Autowired ShipmentRepository repo;       // JPA
    @Autowired JdbcTemplate jdbcTemplate;      // JDBC
    
    @Transactional
    public ShipmentReport generateReport(Long id) {
        // 1. JPA: 도메인 작업
        Shipment s = repo.findById(id).orElseThrow();
        s.markAsReported();
        
        // 2. JdbcTemplate: 복잡 통계
        List<Map<String, Object>> stats = jdbcTemplate.queryForList("""
            WITH ranked AS (
                SELECT region, amount,
                       RANK() OVER (PARTITION BY region ORDER BY amount) AS rk
                FROM shipments
            )
            SELECT * FROM ranked WHERE rk <= 5
            """);
        
        // 3. JpaTM 이 모두 처리
        //    - 같은 Connection
        //    - 단일 트랜잭션
        //    - 원자성 보장
        
        return ShipmentReport.builder()
            .shipment(s)
            .stats(stats)
            .build();
    }
}

// → ILIC = JpaTransactionManager + JPA + JdbcTemplate 혼용
class Shipment { void markAsReported() {} }
ShipmentRepository repo;
interface ShipmentRepository { java.util.Optional<Shipment> findById(Long id); }
JdbcTemplate jdbcTemplate;
class JdbcTemplate { java.util.List<java.util.Map<String, Object>> queryForList(String s) { return null; } }
class ShipmentReport {
    static Builder builder() { return null; }
    static class Builder {
        Builder shipment(Shipment s) { return this; }
        Builder stats(java.util.List<java.util.Map<String, Object>> s) { return this; }
        ShipmentReport build() { return null; }
    }
}
@interface Service {}
@interface Autowired {}
@interface Transactional {}

7.8 자기 점검 답변

JPA + JdbcTemplate 혼용 환경의 TM 선택은?

:
1. JpaTM:

  • 혼용 시 표준
  1. 마법:

    • DataSource 도 인식
  2. 단일 트랜잭션:

    • 보장
  3. 주의:

    • flush 시점 / 캐시

8️⃣ Spring Boot 자동 구성

8.1 의존성 기반 자동

의존성 기반 자동:

  build.gradle 의존성 →
  Spring Boot 자동 구성:

  spring-boot-starter-data-jpa:
    → JpaTransactionManager 자동

  spring-boot-starter-jdbc (만):
    → DataSourceTransactionManager 자동

  둘 다:
    → JpaTransactionManager 자동 (JPA 우선)

8.2 자동 등록 빈

Spring Boot 의 자동 빈 (JPA):

  1. HikariDataSource (DataSource)
  2. EntityManagerFactory
  3. JpaTransactionManager (PlatformTransactionManager)
  4. JdbcTemplate (있으면)
  5. NamedParameterJdbcTemplate

  모두 자동 / 연결

8.3 application.yml 만

# application.yml (Spring Boot 자동)
spring:
  datasource:
    url: jdbc:mysql://...
    username: ...
    password: ...
    hikari:
      maximum-pool-size: 20
  
  jpa:
    hibernate:
      ddl-auto: validate
    properties:
      hibernate:
        format_sql: true
    open-in-view: false

# 코드 X
# 자동 구성

8.4 수동 빈 설정 (필요 시)

// 수동 빈 설정 (다중 DataSource 등)
@Configuration
public class TransactionConfig {
    
    @Primary
    @Bean
    public PlatformTransactionManager transactionManager(
            @Qualifier("mainEmf") EntityManagerFactory emf) {
        return new JpaTransactionManager(emf);
    }
    
    @Bean
    public PlatformTransactionManager logTransactionManager(
            @Qualifier("logDataSource") DataSource dataSource) {
        return new DataSourceTransactionManager(dataSource);
    }
}

// 사용 시 명시
@Transactional("transactionManager")
public void mainBusiness() { ... }

@Transactional("logTransactionManager")
public void logBusiness() { ... }
class JpaTransactionManager implements PlatformTransactionManager {
    JpaTransactionManager(EntityManagerFactory emf) {}
}
class DataSourceTransactionManager implements PlatformTransactionManager {
    DataSourceTransactionManager(DataSource ds) {}
}
interface PlatformTransactionManager {}
class EntityManagerFactory {}
interface DataSource {}
@interface Configuration {}
@interface Primary {}
@interface Bean {}
@interface Qualifier { String value(); }
@interface Transactional { String value(); }

8.5 자동 구성의 가치

자동 구성의 가치:

  1. 빠른 시작:
     - 의존성만
     - 코드 X

  2. 표준:
     - 모두 같은 패턴
     - 학습 ↓

  3. 안전:
     - 검증된 설정
     - 실수 X

  4. 유지보수:
     - Spring Boot 가 관리

→ Spring Boot 의 강점

8.6 ILIC 의 맥락

// ILIC build.gradle
dependencies {
    implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
    // 자동 포함:
    // - JPA + Hibernate
    // - Spring Data JPA
    // - JpaTransactionManager (자동)
    // - HikariCP (자동)
    
    runtimeOnly 'com.mysql:mysql-connector-j'
}
// ILIC 의 코드 (빈 설정 없음, 자동)

@SpringBootApplication
public class IlicApplication {
    public static void main(String[] args) {
        SpringApplication.run(IlicApplication.class, args);
    }
}

// → Spring Boot 가 모두 자동
// → JpaTransactionManager 자동 등록
// → 모든 @Transactional 이 이걸 사용
@interface SpringBootApplication {}
class SpringApplication {
    static void run(Class<?> c, String[] args) {}
}

8.7 자기 점검 답변

Spring Boot 자동 구성은?

:
1. 자동:

  • 의존성 기반
  1. 자동 빈:

    • DataSource / EMF / TM / JdbcTemplate
  2. application.yml:

    • 설정만
  3. 가치:

    • 빠름 / 표준 / 안전

9️⃣ ILIC 의 선택 + Phase 6.3 예고

9.1 ILIC 의 선택 종합

ILIC 의 선택:

  주력 TM:
    - JpaTransactionManager (자동)

  도구 조합:
    - JPA (주력) ✓
    - Spring Data JPA ✓
    - Querydsl ✓
    - JdbcTemplate (보조 - 복잡 통계) ✓

  통합 트랜잭션:
    - JpaTM 이 모두 처리
    - 단일 Connection
    - 원자성

→ 한국 기업 표준

9.2 의존성 확인

// ILIC 의존성
dependencies {
    // 핵심
    implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
    
    // Querydsl
    implementation 'com.querydsl:querydsl-jpa:5.0.0:jakarta'
    annotationProcessor 'com.querydsl:querydsl-apt:5.0.0:jakarta'
    
    // (자동 포함: spring-boot-starter-jdbc → JdbcTemplate)
    
    // 추가
    implementation 'org.springframework.boot:spring-boot-starter-web'
    
    // DB
    runtimeOnly 'com.mysql:mysql-connector-j'
}

9.3 Phase 6.3 예고

Phase 6.3 — 사용 전후 비교:

  Before (수동):
    - tx.begin / commit / rollback
    - 보일러플레이트
    - 함정

  After (PlatformTM):
    - 인터페이스 의존
    - 일관 코드
    - 추상화

  After 2 (TransactionTemplate):
    - 람다
    - 자동

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

9.4 진화의 흐름

진화의 흐름:

  Phase 5 (수동):
    - 결합 / 함정
    - 자동화 동기

  Phase 6 (PlatformTM):
    - 인터페이스 추상화
    - 구현체 분리
    - TransactionTemplate

  Phase 7 (@Transactional):
    - 어노테이션 + AOP
    - 5가지 함정
    - 면접 정점

→ 점진적 자동화

9.5 면접 단골 질문 매핑

Q핵심 답변
3 구현체?DS/Hibernate/JPA TM
DataSourceTM?JDBC / Connection
HibernateTM?Hibernate 직접 (드묾)
JpaTM?JPA / 현대 표준
선택 기준?사용 기술
혼용?JpaTM
ThreadLocal?트랜잭션 동기화
Spring Boot 자동?의존성 기반
다중 TM?@Qualifier
ILIC 선택?JpaTM

9.6 자기 점검 체크리스트

3 구현체

  • 개요

DataSourceTM

  • 동작

HibernateTM

  • 드묾

JpaTM

  • 표준

내부 동작

  • 차이

선택 기준

  • 매트릭스

혼용

  • JpaTM

Spring Boot

  • 자동

ILIC

  • JpaTM

9.7 추가 심화 질문

Q1: ChainedTransactionManager?

답:

  • 여러 TM 묶음
  • 순차 commit
  • 멀티 DB
  • "최선 노력" (XA 아님)

Q2: JtaTransactionManager?

답:

  • XA 분산 트랜잭션
  • 여러 DB / JMS 등
  • Atomikos / Bitronix 등
  • 복잡 / 성능 ↓

Q3: ReactiveTransactionManager?

답:

  • 리액티브 (R2DBC)
  • WebFlux
  • 별도 인터페이스

Q4: 트랜잭션 매니저 변경 시 코드 영향?

답:

  • 거의 X
  • 인터페이스 의존
  • 빈 변경만
  • @Transactional 그대로

Q5: 다중 데이터 소스 + 다중 TM 패턴?

답:

  • @Primary 로 기본
  • @Qualifier 로 명시
  • @Transactional("xxx") 로 선택
  • 분리된 트랜잭션 (XA X)

🎯 핵심 요약 — 3줄 정리

1. 3가지 구현체

  • DataSourceTransactionManager: JDBC / JdbcTemplate, DataSource 받음
  • HibernateTransactionManager: Hibernate 직접 (드묾), SessionFactory
  • JpaTransactionManager: JPA / Spring Data JPA (현대 표준), EntityManagerFactory

2. 선택 기준

  • 사용 기술 따라 → Spring Boot 자동
  • JPA + JdbcTemplate 혼용 시 → JpaTransactionManager (DataSource 도 인식)
  • 같은 Connection / 단일 트랜잭션 보장

3. ILIC = JpaTransactionManager

  • Spring Boot + JPA + Spring Data JPA + Querydsl + JdbcTemplate
  • 모두 같은 트랜잭션
  • 인터페이스 의존 (DIP) → 미래 변경 안전

📚 다음으로...

Unit 6.3 — 사용 전후 비교 (Phase 6 완주)

이번 Unit에서 3가지 구현체를 봤다면, 다음은 사용 전후 비교 (Phase 6 마지막).

  • 수동 트랜잭션 (Before) vs PlatformTM (After) 코드 비교
  • TransactionTemplate 의 람다 활용
  • 점진적 추상화
  • Phase 7 (@Transactional ★★★) 예고

Phase 6 진행 상황

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

7주차 누적 진행

🗂️ Part A (완주)
  ✅ Phase 1-4 (16)

🔄 Part B — 트랜잭션 추상화의 진화
  ✅ Phase 5 (2)
  🎯 Phase 6 (2/3)

총: 20/24 Unit (83%)
profile
Software Developer

0개의 댓글