7주차 Unit 3.3 — JPA 동작 위치

Psj·2026년 6월 1일

F-lab

목록 보기
222/239

Unit 3.3 — JPA 동작 위치

F-LAB JAVA · 7주차 · Phase 3 · JPA 입문


📌 학습 목표

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

  • JPA 동작 위치 (애플리케이션 ↔ JDBC 사이) 는?
  • 계층 그림 4단계는?
  • JPA 가 JDBC 를 대체하는가 ?
  • HikariCP 는 JPA 에서도 활용되는가 ?
  • 6주차 학습이 그대로 통합 되는 의미는?
  • JPA 가 JDBC 호출 흐름은?
  • DataSource 가 JPA 에서 위치 는?
  • Spring Boot 의 자동 구성 은?
  • JPA 의 안 보이는 일 은?

🎯 핵심 한 문장

JPA 는 애플리케이션과 JDBC 사이의 중간 계층으로 자체적으로 DB 와 통신하는 게 아니라 내부적으로는 여전히 JDBC 를 사용하므로 6주차에서 본 DataSource · HikariCP · Connection Pool 같은 인프라가 그대로 활용되며 Spring Boot 가 모두 자동 구성한다.
JPA 의 동작 위치는 애플리케이션 코드와 JDBC 사이의 중간 계층 이다.
4단계 스택은 — (1) Application (객체 코드) → (2) JPA (Hibernate 구현) → (3) JDBC → (4) DB Driver → DB — 로 위에서 아래로 추상화 단계가 명확하다.
JPA 는 JDBC 를 대체하지 않고 위에 얹힌다 — JPA 가 내부적으로 JDBC 의 Connection, PreparedStatement 를 호출해서 SQL 을 실행하므로 JDBC 가 없으면 JPA 도 동작 못 한다.
따라서 6주차에서 본 DataSource (인터페이스), HikariCP (Connection Pool 구현), JDBC Driver 가 모두 JPA 에서도 그대로 활용되며 — 6주차 학습이 7주차 JPA 에서 그대로 통합 되는 게 자바 진영 추상화의 아름다움이다.
Spring Boot 는 이 모든 계층을 자동 구성해 — spring.datasource.* 설정만으로 HikariDataSource 빈 → EntityManagerFactory → EntityManager 까지 한 번에 준비된다.

비유 — 4층 건물의 계층

JPA 동작 위치 = 4층 건물:

[4층] Application (사람, 객체):
  - 비즈니스 로직
  - 객체로 작업
  - "Shipment 가져와"

[3층] JPA (Hibernate, 통역사):
  - 객체 ↔ SQL 자동 변환
  - 영속성 컨텍스트
  - "SELECT 만들자"

[2층] JDBC (배관, 자바 표준):
  - SQL 실행 인터페이스
  - Connection / Statement
  - 6주차에서 학습

[1층] DataSource + Driver (수도꼭지):
  - HikariCP (커넥션 풀)
  - DB Driver
  - 6주차에서 학습

[지하] DB (수원지):
  - MySQL / PostgreSQL
  - 실제 데이터

위에서 아래로:
  - 추상화 ↑→↓
  - 4층은 객체로만
  - 1층은 가장 저수준

핵심:
  - JPA 는 JDBC 위에
  - JDBC 가 없으면 JPA 도 X
  - 6주차 학습 그대로

ILIC:
  - 4층: Service, Repository
  - 3층: Hibernate (Spring Data JPA)
  - 2층: JDBC (그대로)
  - 1층: HikariCP (6주차 그대로)
  - 지하: MySQL 8.x

→ JPA = JDBC 위 계층, 6주차 인프라 그대로 활용, Spring Boot 가 모두 자동.


🧭 9개 섹션 로드맵

1. 동작 위치
2. 4단계 계층 그림
3. JPA 가 JDBC 대체 X
4. JPA 의 JDBC 호출 흐름
5. DataSource 의 위치
6. HikariCP 와 JPA
7. Spring Boot 자동 구성
8. 6주차 학습의 통합
9. 안 보이는 일들

1️⃣ 동작 위치

1.1 중간 계층

JPA 의 위치:

  애플리케이션과 JDBC 사이:
    - 위: 객체로 작업 (애플리케이션)
    - 아래: JDBC 로 SQL 실행
    - 중간: JPA 가 변환

→ 중간 계층 (Middle Layer)

1.2 추상화 사다리

추상화 사다리:

  높음 (객체 위주)
       ↓
  Application
       ↓ JPA API
  JPA (객체 ↔ SQL 변환)
       ↓ JDBC API
  JDBC (SQL 실행)
       ↓ DB Protocol
  DB
       ↑
  낮음 (실제 데이터)

1.3 핵심 정신

핵심 정신:

  JPA 의 역할:
    - "객체와 RDB 의 다리"
    - 자기 자신은 DB 와 직접 통신 X
    - JDBC 를 사용해서 통신

→ 위에 얹는다 (overlay)

1.4 ILIC 의 맥락

ILIC 의 계층 (Spring Boot)

┌─────────────────────────────────────┐
│   ShipmentService (비즈니스 로직)     │
│   ShipmentController (REST API)     │
└──────────────┬──────────────────────┘
               │ Repository.findById(1L)
               ↓
┌─────────────────────────────────────┐
│   Spring Data JPA Repository        │
│   ShipmentRepository (인터페이스)    │
└──────────────┬──────────────────────┘
               │ JPA API
               ↓
┌─────────────────────────────────────┐
│   JPA (Hibernate 구현체)             │
│   - 객체 → SQL                       │
│   - SQL → 객체                       │
│   - 영속성 컨텍스트                  │
└──────────────┬──────────────────────┘
               │ JDBC API
               ↓
┌─────────────────────────────────────┐
│   JDBC (6주차 학습)                  │
│   - Connection, Statement, ResultSet│
└──────────────┬──────────────────────┘
               │ DataSource.getConnection()
               ↓
┌─────────────────────────────────────┐
│   HikariCP (6주차 학습)              │
│   - Connection Pool                 │
└──────────────┬──────────────────────┘
               ↓
┌─────────────────────────────────────┐
│   MySQL (DB)                        │
└─────────────────────────────────────┘

1.5 자기 점검 답변

JPA 동작 위치 (애플리케이션 ↔ JDBC 사이) 는?

:
1. 위치:

  • 중간 계층
  1. :

    • 애플리케이션
  2. 아래:

    • JDBC
  3. 역할:

    • 객체 ↔ SQL 변환

2️⃣ 4단계 계층 그림

2.1 상세 계층

4 단계 계층:

┌─────────────────────────────────┐
│  ① Application Code             │
│     (Item, Member, Order 객체)   │
└────────────┬────────────────────┘
             │ JPA API (em.find, em.persist)
             ↓
┌─────────────────────────────────┐
│  ② JPA (Hibernate 구현체)        │
│     - 객체 ↔ SQL 변환             │
│     - 영속성 컨텍스트              │
│     - Dirty Checking              │
└────────────┬────────────────────┘
             │ JDBC API
             ↓
┌─────────────────────────────────┐
│  ③ JDBC                         │
│     - Connection / Statement     │
│     - PreparedStatement          │
│     - ResultSet                  │
└────────────┬────────────────────┘
             │ DB Driver Protocol
             ↓
┌─────────────────────────────────┐
│  ④ DB Driver                    │
│     - MySQL Connector/J         │
│     - PostgreSQL JDBC           │
└────────────┬────────────────────┘
             ↓
┌─────────────────────────────────┐
│     DB (MySQL/PostgreSQL/...)    │
└─────────────────────────────────┘

2.2 각 계층의 역할

각 계층의 역할:

① Application:
   - 객체로 작업
   - 비즈니스 로직
   - "Shipment 객체 저장"

② JPA:
   - 객체 → SQL 자동
   - 변경 감지
   - 캐시 (1차)

③ JDBC:
   - 자바 표준 인터페이스
   - SQL 실행
   - 결과 처리

④ DB Driver:
   - DB 별 구현
   - 네트워크 통신
   - 프로토콜 변환

2.3 책임 분리

책임 분리:

  각 계층:
    - 한 가지 책임만
    - 인터페이스로 분리
    - 5주차 SoC 원칙

→ 좋은 계층 설계

2.4 OSI 모델과 비교

OSI 모델 비교:

  네트워크 OSI 7 계층:
    - 각 계층 추상화
    - 위는 아래 모름
    - 인터페이스만

  JPA 4 계층:
    - 같은 정신
    - 위는 아래 추상화
    - 인터페이스 의존

→ 좋은 디자인 패턴

2.5 ILIC 의 맥락

// 4 계층 (ILIC)

// ① Application
@Service
class ShipmentService {
    @Autowired ShipmentRepository repo;
    
    public void process(Long id) {
        Shipment s = repo.findById(id).orElseThrow();
        s.markAsShipped();   // 비즈니스 로직 (객체)
        // JPA 자동 UPDATE (트랜잭션 commit 시)
    }
}

// ② JPA (Hibernate)
// - repo.findById(id) → SQL 생성
// - SELECT * FROM shipments WHERE id = ?
// - ResultSet → Shipment 객체

// ③ JDBC
// - Connection conn = dataSource.getConnection();
// - PreparedStatement ps = conn.prepareStatement(sql);
// - ResultSet rs = ps.executeQuery();
// (6주차 학습)

// ④ DB Driver
// - mysql-connector-j
// - MySQL 과 TCP 통신

// ⑤ MySQL
// - 실제 데이터 저장
class Shipment { void markAsShipped() {} }
ShipmentRepository repo;
interface ShipmentRepository { java.util.Optional<Shipment> findById(Long id); }

2.6 자기 점검 답변

4단계 계층 그림은?

:
1. 4단계:

  • App / JPA / JDBC / Driver
  1. 상하:

    • 위 → 아래 호출
  2. 책임:

    • 각 계층 분리
  3. 추상화:

    • 위는 아래 모름

3️⃣ JPA 가 JDBC 대체 X

3.1 대체하지 않음

JPA 는 JDBC 대체 X:

  JPA 는:
    - JDBC 위에 얹는다
    - JDBC 를 사용한다
    - JDBC 가 없으면 동작 X

  ≠ JDBC 제거

→ JDBC + JPA (둘 다 필요)

3.2 의존성 확인

// build.gradle (Spring Boot)
dependencies {
    implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
    // ↑ 자동 포함:
    // - jakarta.persistence-api (JPA 인터페이스)
    // - org.hibernate:hibernate-core (JPA 구현)
    // - spring-jdbc (JDBC 추상화)
    // - jdbc 표준 (java.sql)
    
    runtimeOnly 'com.mysql:mysql-connector-j'
    // ↑ JDBC Driver
}
// JDBC 가 빠지면 JPA 못 씀

3.3 6주차 → 7주차

6주차 → 7주차:

  6주차 학습 (JDBC):
    - DriverManager / Connection
    - Statement / PreparedStatement
    - ResultSet
    - DataSource / HikariCP
    - 트랜잭션 ACID

  7주차 (JPA):
    - 6주차 내용 그대로 사용
    - + 객체 매핑 자동
    - + SQL 자동
    - + 객체 그래프

→ 6주차 위에 7주차

3.4 JDBC 직접 사용 가능

// JPA 와 JDBC 같이 사용 가능 (드물게)

// JPA Repository
@Autowired ShipmentRepository repo;

// JdbcTemplate (보조)
@Autowired JdbcTemplate jdbcTemplate;

// 같이 사용
@Transactional
public void process() {
    // JPA 로 단순 CRUD
    Shipment s = repo.findById(1L).orElseThrow();
    s.setStatus("SHIPPED");
    
    // JdbcTemplate 으로 복잡 통계
    List<Map<String, Object>> stats = jdbcTemplate.queryForList(
        "SELECT region, COUNT(*) FROM shipments GROUP BY region"
    );
    
    // 같은 트랜잭션 / 같은 Connection
}
class Shipment { void setStatus(String s) {} }
ShipmentRepository repo;
JdbcTemplate jdbcTemplate;
class JdbcTemplate {
    java.util.List<java.util.Map<String, Object>> queryForList(String s) { return null; }
}
interface ShipmentRepository {
    java.util.Optional<Shipment> findById(Long id);
}

3.5 ILIC 의 맥락

// ILIC 의 JDBC + JPA 공존
@Service
public class ShipmentService {
    @Autowired ShipmentRepository repo;      // JPA
    @Autowired JdbcTemplate jdbcTemplate;     // JDBC (보조)
    
    @Transactional
    public void monthlyReport() {
        // JPA: 도메인 작업
        List<Shipment> active = repo.findByStatus("SHIPPED");
        active.forEach(s -> {
            s.calculateMonthlyFee();
            // 자동 UPDATE
        });
        
        // JdbcTemplate: 복잡 통계
        List<Map<String, Object>> stats = jdbcTemplate.queryForList("""
            SELECT region, COUNT(*), SUM(amount)
            FROM shipments_view
            GROUP BY region
            """);
        
        // 두 도구가 같은 Connection / 트랜잭션
        // → 6주차 인프라 공유
    }
}
class Shipment { void calculateMonthlyFee() {} }
ShipmentRepository repo;
JdbcTemplate jdbcTemplate;
class JdbcTemplate {
    java.util.List<java.util.Map<String, Object>> queryForList(String s) { return null; }
}
interface ShipmentRepository {
    java.util.List<Shipment> findByStatus(String s);
}

3.6 자기 점검 답변

JPA 가 JDBC 를 대체하는가?

:
1. 대체 X:

  • 위에 얹음
  1. JDBC 필수:

    • 없으면 동작 X
  2. 공존:

    • 같이 사용 가능
  3. 6주차 그대로:

    • 학습 통합

4️⃣ JPA 의 JDBC 호출 흐름

4.1 흐름 다이어그램

JPA → JDBC 호출 흐름:

  ① 애플리케이션:
     repo.findById(1L)
            ↓
  ② JPA:
     - SQL 생성: "SELECT * FROM shipments WHERE id = ?"
     - 영속성 컨텍스트 확인 (캐시)
            ↓
  ③ JDBC:
     conn = dataSource.getConnection();  // 풀에서
     ps = conn.prepareStatement(sql);
     ps.setLong(1, 1);
     rs = ps.executeQuery();
            ↓
  ④ DB:
     SELECT 실행, 결과 반환
            ↑
  ③ JDBC:
     rs.next();
     rs.getLong("id"), rs.getString("bl_no") ...
            ↑
  ② JPA:
     ResultSet → Shipment 객체
     영속성 컨텍스트 저장
            ↑
  ① 애플리케이션:
     Shipment 반환

4.2 단계별 코드 (JPA 내부, 개념)

// JPA 의 내부 동작 (개념적 의사 코드)

public Shipment find(Class<Shipment> clazz, Long id) {
    // 1. 영속성 컨텍스트 확인
    Shipment cached = persistenceContext.get(clazz, id);
    if (cached != null) return cached;
    
    // 2. SQL 생성
    String sql = generateSelectSQL(clazz, id);   // "SELECT ... WHERE id = ?"
    
    // 3. JDBC 호출
    try (Connection conn = dataSource.getConnection();
         PreparedStatement ps = conn.prepareStatement(sql)) {
        ps.setLong(1, id);
        try (ResultSet rs = ps.executeQuery()) {
            if (rs.next()) {
                // 4. 객체 변환
                Shipment shipment = new Shipment();
                shipment.setId(rs.getLong("id"));
                shipment.setBlNo(rs.getString("bl_no"));
                // ... 모든 필드
                
                // 5. 영속성 컨텍스트 저장
                persistenceContext.put(shipment);
                
                return shipment;
            }
        }
    }
    return null;
}
class Shipment { void setId(Long id) {} void setBlNo(String s) {} }
class PersistenceContext {
    <T> T get(Class<T> c, Object id) { return null; }
    void put(Object o) {}
}
PersistenceContext persistenceContext;
DataSource dataSource;
String generateSelectSQL(Class<?> c, Object id) { return null; }
interface DataSource { Connection getConnection() throws SQLException; }

4.3 영속성 컨텍스트의 역할

영속성 컨텍스트:

  1차 캐시:
    - 같은 트랜잭션 내 id 같으면 같은 객체 반환
    - 두 번째 find 는 SQL X (캐시)

→ JDBC 호출 최소화

4.4 변경 감지 (Dirty Checking)

변경 감지 (Dirty Checking):

  객체 수정 시:
    1. JPA 가 변경 감지 (영속성 컨텍스트)
    2. 트랜잭션 commit 시
    3. UPDATE SQL 자동 생성
    4. JDBC 로 실행

→ 명시적 UPDATE 불필요

4.5 flush

flush:

  영속성 컨텍스트 → DB 반영:
    - 자동 (트랜잭션 commit 시)
    - 또는 명시적 (em.flush())
    - SQL 묶음 실행

→ 효율적 (배치)

4.6 ILIC 의 맥락

// ILIC 의 JPA → JDBC 흐름

@Transactional
public void updateStatus(Long id, String newStatus) {
    // 1. find 호출
    Shipment s = shipmentRepository.findById(id).orElseThrow();
    // JPA 내부:
    // - 영속성 컨텍스트 확인
    // - 없으면 SQL 생성
    // - JDBC 호출 (Connection / PreparedStatement / ResultSet)
    // - 객체 변환 후 영속성 컨텍스트 저장
    
    // 2. 객체 수정
    s.setStatus(newStatus);
    // JPA 내부:
    // - 영속성 컨텍스트의 객체 변경
    // - Dirty Checking 표시 (변경 감지)
    
    // 3. 메서드 종료 → 트랜잭션 commit
    // JPA 내부:
    // - flush (영속성 컨텍스트 → DB)
    // - UPDATE SQL 자동 생성
    // - JDBC 로 실행
    // - Connection 반환 (HikariCP 풀로)
}
// → 개발자는 객체로만
// → JPA + JDBC 자동
class Shipment { void setStatus(String s) {} }
ShipmentRepository shipmentRepository;
interface ShipmentRepository { java.util.Optional<Shipment> findById(Long id); }

4.7 자기 점검 답변

JPA 의 JDBC 호출 흐름은?

:
1. 흐름:

  • App → JPA → JDBC → DB
  1. JPA 내부:

    • SQL 생성 + JDBC 호출
  2. 영속성 컨텍스트:

    • 1차 캐시
  3. Dirty Checking:

    • 자동 UPDATE

5️⃣ DataSource 의 위치

5.1 DataSource 의 역할

DataSource 의 역할:

  - Connection 제공
  - 풀 (HikariCP) 관리
  - 자바 표준 인터페이스 (javax.sql)

  6주차 학습:
    - 6주차 Phase 5 (DataSource 인터페이스)
    - 6주차 Phase 4 (Connection Pool)

5.2 JPA 의 DataSource 사용

JPA 의 DataSource 사용:

  EntityManagerFactory:
    - DataSource 주입 받음
    - Connection 필요 시 getConnection() 호출

  → 6주차 DataSource 그대로

5.3 흐름

흐름:

  ① JPA 가 SQL 실행 필요
        ↓
  ② DataSource.getConnection() 호출
        ↓
  ③ HikariCP 풀에서 Connection 빌림
        ↓
  ④ JDBC PreparedStatement 실행
        ↓
  ⑤ ResultSet 처리
        ↓
  ⑥ Connection 반환 (HikariCP 풀로)

5.4 Spring Boot 의 자동 구성

Spring Boot 자동:

  application.yml:
    spring:
      datasource:
        url: jdbc:mysql://...
        username: ...
        password: ...
        hikari:
          maximum-pool-size: 20

  Spring Boot 자동:
    1. HikariDataSource 빈 생성 (DataSource)
    2. EntityManagerFactory 빈 (JPA + DataSource)
    3. TransactionManager
    4. 모두 연결

5.5 ILIC 의 맥락

# ILIC application.yml
spring:
  datasource:
    url: jdbc:mysql://prod-mysql:3306/ilic
    username: ilic_user
    password: ${DB_PASSWORD}
    hikari:
      maximum-pool-size: 20
      minimum-idle: 5
      connection-timeout: 30000
  jpa:
    hibernate:
      ddl-auto: validate
    properties:
      hibernate:
        dialect: org.hibernate.dialect.MySQLDialect
        format_sql: true
    show-sql: false   # 운영
// ILIC 코드: 자동 연결
@Autowired
private DataSource dataSource;   // HikariDataSource

@PersistenceContext
private EntityManager em;        // JPA + Hibernate

// em.find() 호출:
// 1. JPA (Hibernate) 가 SQL 생성
// 2. dataSource.getConnection() 호출
// 3. HikariCP 풀에서 Connection
// 4. JDBC 로 SQL 실행
// 5. 결과 객체 변환
// → 6주차 + 7주차 통합
class EntityManager {}
@interface PersistenceContext {}
interface DataSource {}
DataSource dataSource;
EntityManager em;

5.6 자기 점검 답변

DataSource 가 JPA 에서 위치는?

:
1. 역할:

  • Connection 제공
  1. JPA 사용:

    • EntityManagerFactory
  2. HikariCP:

    • 풀 그대로
  3. 자동:

    • Spring Boot

6️⃣ HikariCP 와 JPA

6.1 HikariCP 는 JPA 에서도

HikariCP 의 위치:

  6주차 학습:
    - 가장 빠른 Connection Pool
    - Spring Boot 기본

  7주차 (JPA):
    - 그대로 활용
    - JPA 가 DataSource 통해 사용
    - 6주차 학습 그대로 통합

6.2 풀의 가치

풀의 가치 (JPA 에서도):

  - Connection 생성 비용 ↓
  - 동시 사용자 처리 ↑
  - 응답 시간 ↓
  - DB 부하 ↓

→ JPA 도 마찬가지

6.3 사용 흐름

사용 흐름:

  1. JPA 가 SQL 실행 필요
  2. dataSource.getConnection() 호출
  3. HikariCP 풀에서 빌림 (대기 X, 즉시)
  4. SQL 실행
  5. JPA 가 작업 끝
  6. conn.close() 호출 (JPA 내부)
  7. HikariCP 가 풀로 반환 (재사용)

6.4 풀 크기 설정

# 풀 크기 (운영 환경)
spring:
  datasource:
    hikari:
      maximum-pool-size: 20      # 동시 Connection 최대
      minimum-idle: 5            # 최소 유지
      connection-timeout: 30000  # 대기 시간 (ms)
      idle-timeout: 600000       # 유휴 시간
      max-lifetime: 1800000      # 최대 생명 시간

# JPA / JDBC 동일

6.5 6주차 ↔ 7주차

6주차 ↔ 7주차:

6주차 Phase 4 — Connection Pool:
  - HikariCP 도입
  - 풀의 가치
  - 풀 크기 결정

  → 7주차에서 그대로
  → JPA 가 활용

→ 학습 누적 가치

6.6 ILIC 의 맥락

HikariCP + JPA (ILIC)

ILIC 의 6주차 → 7주차:

6주차 학습:
  - HikariCP 도입
  - maximum-pool-size = 20
  - 운영 안정

7주차 (JPA 도입):
  - HikariCP 그대로
  - JPA 가 자동 사용
  - 풀 효과 그대로

설정:
  - 6주차 application.yml 의 hikari 그대로
  - jpa 설정만 추가
  - 자동 통합

성능:
  - 풀 효과 (Connection 재사용)
  - + JPA 1차 캐시 (SQL 절약)
  - 시너지

→ ILIC = 6주차 + 7주차 = 통합 시너지

6.7 자기 점검 답변

HikariCP 는 JPA 에서도 활용되는가?

:
1. YES:

  • 그대로 활용
  1. JPA:

    • DataSource 통해
  2. 풀 효과:

    • 동일
  3. 6주차 학습:

    • 그대로 통합

7️⃣ Spring Boot 자동 구성

7.1 자동 구성

Spring Boot 자동 구성:

  spring-boot-starter-data-jpa:
    - DataSource 자동 (HikariCP)
    - EntityManagerFactory 자동
    - TransactionManager 자동
    - Spring Data JPA 활성화

→ application.yml 만 설정

7.2 자동 생성되는 빈

자동 생성 빈:

  1. DataSource (HikariDataSource)
  2. EntityManagerFactory (Hibernate)
  3. EntityManager (각 트랜잭션)
  4. PlatformTransactionManager
     - JpaTransactionManager
  5. JpaRepositoryFactory
     - Repository 자동 구현

7.3 의존성

// build.gradle 한 줄
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'

// 자동 포함:
// - jakarta.persistence-api
// - hibernate-core
// - spring-data-jpa
// - spring-orm
// - spring-jdbc
// - HikariCP

runtimeOnly 'com.mysql:mysql-connector-j'   // Driver

7.4 설정 (application.yml)

spring:
  # 1. DataSource (HikariCP)
  datasource:
    url: jdbc:mysql://localhost:3306/ilic
    username: ilic_user
    password: secret
    hikari:
      maximum-pool-size: 20

  # 2. JPA / Hibernate
  jpa:
    hibernate:
      ddl-auto: validate    # none / create / update / validate
    properties:
      hibernate:
        dialect: org.hibernate.dialect.MySQLDialect
        format_sql: true
        default_batch_fetch_size: 100
    show-sql: true

# 끝. 코드 X

7.5 자동 구성의 가치

자동 구성의 가치:

  Spring Boot 등장 전:
    - 수십 줄 XML 설정
    - 빈 정의 직접
    - 의존성 직접 관리

  Spring Boot:
    - application.yml 만
    - 자동
    - 관례 따르기 (Convention over Configuration)

→ 생산성 극대화

7.6 ILIC 의 맥락

# ILIC application.yml (실제)
spring:
  application:
    name: ilic
  
  datasource:
    url: jdbc:mysql://${DB_HOST}:3306/ilic?serverTimezone=Asia/Seoul&characterEncoding=UTF-8
    username: ${DB_USERNAME}
    password: ${DB_PASSWORD}
    driver-class-name: com.mysql.cj.jdbc.Driver
    hikari:
      maximum-pool-size: 20
      minimum-idle: 5
      connection-timeout: 30000
      max-lifetime: 1800000
  
  jpa:
    hibernate:
      ddl-auto: validate
    properties:
      hibernate:
        dialect: org.hibernate.dialect.MySQLDialect
        format_sql: true
        use_sql_comments: true
        default_batch_fetch_size: 100
    open-in-view: false   # OSIV 비활성화
    show-sql: false       # 운영

7.7 자기 점검 답변

Spring Boot 의 자동 구성은?

:
1. 자동:

  • DataSource / JPA / TX
  1. 자동 빈:

    • 여러 개
  2. 의존성:

    • starter 1 줄
  3. 설정:

    • application.yml

8️⃣ 6주차 학습의 통합

8.1 그대로 통합

6주차 학습 → 7주차 통합:

  6주차 학습한 것:
    ✅ JDBC (Connection, Statement, ResultSet)
    ✅ DataSource (인터페이스 추상화)
    ✅ HikariCP (Connection Pool)
    ✅ 트랜잭션 ACID
    ✅ JdbcTemplate
    ✅ DataSourceTransactionManager

  7주차 (JPA) 에서:
    - 모두 그대로 활용
    - JPA 가 위에 얹힘
    - 6주차 = JPA 의 기반

8.2 학습 누적 가치

학습 누적 가치:

  6주차 단단히 학습 →
  7주차 JPA 깊이 이해

  6주차 부실 →
  7주차 JPA 혼란

→ 6주차가 7주차의 기반
→ 박승제도 6주차부터 차근차근

8.3 트러블슈팅에서 보임

트러블슈팅:

  JPA 문제 발생 시:
    - SQL 어떻게 만들어졌나? (show-sql, 6주차 학습)
    - Connection 누수? (HikariCP, 6주차)
    - 트랜잭션 안 풀림? (ACID, 6주차)
    - N+1? (JOIN 이해, 7주차 + 6주차)

→ 6주차 학습이 직접 활용

8.4 통합의 아름다움

통합의 아름다움:

  자바 진영의 추상화:
    - 인터페이스 (JDBC, JPA)
    - 구현체 (Driver, Hibernate)
    - 표준 (자바 명세)
    - 5주차 패턴

  학습 누적:
    - 각 주차가 독립적이지만
    - 위로 갈수록 통합
    - 7주차 = 1-6주차의 결정체

8.5 ILIC 의 맥락

ILIC 의 학습 누적

박승제 의 학습 흐름:
  1주차: 자바 OOP
  2주차: JVM
  3주차: 람다 / 함수형
  4주차: 동시성
  5주차: Spring DI / 패턴
  6주차: DB 접근 (JDBC/Pool/DataSource/ACID/JdbcTemplate)
  7주차: ORM / JPA / 트랜잭션 추상화

ILIC 의 실제 (1주차 ~ 7주차 그대로):
  - JVM 이해 → 성능 튜닝
  - 람다 → JPA RowMapper / Stream
  - 동시성 → 트랜잭션 격리
  - DI → Spring Boot
  - JDBC / Pool / DataSource → JPA 의 기반
  - ACID → @Transactional
  - JdbcTemplate → JPA 와 혼용

→ 102 테이블 운영의 기반
→ 7주차 = 모든 학습의 응축

8.6 자기 점검 답변

6주차 학습이 그대로 통합되는 의미는?

:
1. 통합:

  • 6주차 그대로
  1. 누적 가치:

    • 7주차의 기반
  2. 트러블슈팅:

    • 6주차 활용
  3. 아름다움:

    • 자바 추상화

9️⃣ 안 보이는 일들

9.1 JPA 가 안 보이게 하는 것

JPA 가 안 보이게 하는 것:

  1. SQL 생성
  2. Connection 획득 / 반환
  3. PreparedStatement 생성
  4. ResultSet 처리
  5. 객체 ↔ ResultSet 변환
  6. 트랜잭션 동기화
  7. 영속성 컨텍스트 관리
  8. Dirty Checking
  9. 캐시 (1차)
  10. 객체 그래프 로딩 (Lazy/Eager)

9.2 6주차의 자원 관리도 자동

6주차 자원 관리:

  JDBC 직접:
    - try/catch/finally
    - close 들

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

  JPA (7주차):
    - 자원 관리 자동
    - + 그 외 모두 자동

→ 추상화 깊어짐

9.3 보이는 것만

보이는 것만 (개발자):

  - @Entity 정의
  - Repository 인터페이스
  - 비즈니스 로직 (객체 작업)
  - @Transactional

  나머지 모두 자동

9.4 추상화의 양면

추상화의 양면:

  장점:
    - 생산성 ↑
    - 가독성 ↑
    - 비즈니스 집중

  단점:
    - "마법" 같음
    - 내부 모르면 디버깅 ↓
    - 성능 튜닝 어려움
    - 학습곡선 ↑

→ 내부 이해 필요 (이번 Unit 의 의의)

9.5 면접 단골 질문 매핑

Q핵심 답변
JPA 위치?중간 계층
4단계?App/JPA/JDBC/Driver
JDBC 대체?NO, 위에 얹음
HikariCP?그대로 활용
호출 흐름?App → JPA → JDBC → DB
DataSource?JPA 가 사용
Spring Boot?자동 구성
6주차 통합?그대로
안 보이는 일?자원 / 캐시 / 변경 감지
추상화의 양면?장단점

9.6 자기 점검 체크리스트

위치

  • 중간 계층

4단계

  • App/JPA/JDBC/Driver

대체 X

  • JDBC 필수

호출 흐름

  • App → DB

DataSource

  • 6주차 그대로

HikariCP

  • 통합

Spring Boot

  • 자동

6주차 통합

  • 누적

9.7 추가 심화 질문

Q1: EntityManagerFactory vs EntityManager?

답:

  • Factory: 애플리케이션당 1 (싱글톤)
  • Manager: 트랜잭션당 1
  • Factory 가 Manager 생성
  • 6주차 DataSource vs Connection 과 유사

Q2: OSIV (Open Session In View)?

답:

  • View 까지 영속성 컨텍스트 유지
  • 기본 ON (Spring Boot)
  • LazyInitializationException 방지
  • 하지만 Connection 점유 길어짐
  • 운영 시 OFF 권장

Q3: JPA flush 시점?

답:

  • 트랜잭션 commit 직전 자동
  • JPQL 실행 전
  • em.flush() 명시
  • FlushModeType 으로 제어

Q4: 영속성 컨텍스트의 4가지 상태?

답:

  • 비영속 (new)
  • 영속 (managed)
  • 준영속 (detached)
  • 삭제 (removed)

Q5: 멀티 DataSource + JPA?

답:

  • @Primary DataSource
  • @Qualifier 로 구분
  • 각자 EntityManagerFactory
  • @Transactional 명시 (특정 TM)

🎯 핵심 요약 — 3줄 정리

1. JPA 의 위치 = 애플리케이션과 JDBC 사이 중간 계층

  • 4단계: Application → JPA (Hibernate) → JDBC → DB Driver → DB
  • 위에 얹는 추상화 (대체 X)

2. JDBC + JPA 공존

  • JPA 내부에서 JDBC 호출 (Connection / PreparedStatement / ResultSet)
  • 6주차 학습 (DataSource, HikariCP, ACID) 그대로 활용

3. Spring Boot 자동 구성

  • application.yml 만 설정 → 모든 빈 자동
  • DataSource + EntityManagerFactory + TransactionManager 자동 연결
  • 자바 진영 추상화의 결정체 (1-6주차의 응축)

📚 다음으로...

Unit 3.4 — Spring Data JPA + Querydsl ★ 깊이 파기 (Phase 3 완주)

이번 Unit에서 JPA 위치를 봤다면, 다음은 Spring Data JPA + Querydsl (★ 깊이, Phase 3 마지막).

  • Spring Data JPA: JPA 위 또 다른 추상화
  • Repository 인터페이스 자동 구현
  • 메서드 이름 기반 쿼리 (findByXxx)
  • Querydsl: 타입 안전 동적 쿼리
  • 실무 표준 조합

Phase 3 진행 상황

🌱 Phase 3 — JPA 입문
  ✅ Unit 3.1 SQL Mapper 의 한계
  ✅ Unit 3.2 JPA 의 등장 ★깊이
  ✅ Unit 3.3 JPA 동작 위치 ← 여기
  ⏭ Unit 3.4 Spring Data JPA + Querydsl ★깊이 — Phase 3 완주

7주차 누적 진행

🗂️ Part A — 데이터 모델링과 ORM
  ✅ Phase 1 (5)
  ✅ Phase 2 (2)
  🌱 Phase 3 (3/4)

총: 10/24 Unit

F-LAB JAVA · 7주차 · Phase 3 · Unit 3.3 · 끝

profile
Software Developer

0개의 댓글