F-LAB JAVA · 7주차 · Phase 3 · JPA 입문
이 Unit을 끝내면 다음을 답할 수 있어야 한다.
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 까지 한 번에 준비된다.
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 가 모두 자동.
1. 동작 위치
2. 4단계 계층 그림
3. JPA 가 JDBC 대체 X
4. JPA 의 JDBC 호출 흐름
5. DataSource 의 위치
6. HikariCP 와 JPA
7. Spring Boot 자동 구성
8. 6주차 학습의 통합
9. 안 보이는 일들
JPA 의 위치:
애플리케이션과 JDBC 사이:
- 위: 객체로 작업 (애플리케이션)
- 아래: JDBC 로 SQL 실행
- 중간: JPA 가 변환
→ 중간 계층 (Middle Layer)
추상화 사다리:
높음 (객체 위주)
↓
Application
↓ JPA API
JPA (객체 ↔ SQL 변환)
↓ JDBC API
JDBC (SQL 실행)
↓ DB Protocol
DB
↑
낮음 (실제 데이터)
핵심 정신:
JPA 의 역할:
- "객체와 RDB 의 다리"
- 자기 자신은 DB 와 직접 통신 X
- JDBC 를 사용해서 통신
→ 위에 얹는다 (overlay)
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) │
└─────────────────────────────────────┘
JPA 동작 위치 (애플리케이션 ↔ JDBC 사이) 는?
답:
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/...) │
└─────────────────────────────────┘
각 계층의 역할:
① Application:
- 객체로 작업
- 비즈니스 로직
- "Shipment 객체 저장"
② JPA:
- 객체 → SQL 자동
- 변경 감지
- 캐시 (1차)
③ JDBC:
- 자바 표준 인터페이스
- SQL 실행
- 결과 처리
④ DB Driver:
- DB 별 구현
- 네트워크 통신
- 프로토콜 변환
책임 분리:
각 계층:
- 한 가지 책임만
- 인터페이스로 분리
- 5주차 SoC 원칙
→ 좋은 계층 설계
OSI 모델 비교:
네트워크 OSI 7 계층:
- 각 계층 추상화
- 위는 아래 모름
- 인터페이스만
JPA 4 계층:
- 같은 정신
- 위는 아래 추상화
- 인터페이스 의존
→ 좋은 디자인 패턴
// 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); }
4단계 계층 그림은?
답:
1. 4단계:
상하:
책임:
추상화:
JPA 는 JDBC 대체 X:
JPA 는:
- JDBC 위에 얹는다
- JDBC 를 사용한다
- JDBC 가 없으면 동작 X
≠ JDBC 제거
→ JDBC + JPA (둘 다 필요)
// 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 못 씀
6주차 → 7주차:
6주차 학습 (JDBC):
- DriverManager / Connection
- Statement / PreparedStatement
- ResultSet
- DataSource / HikariCP
- 트랜잭션 ACID
7주차 (JPA):
- 6주차 내용 그대로 사용
- + 객체 매핑 자동
- + SQL 자동
- + 객체 그래프
→ 6주차 위에 7주차
// 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);
}
// 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);
}
JPA 가 JDBC 를 대체하는가?
답:
1. 대체 X:
JDBC 필수:
공존:
6주차 그대로:
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 반환
// 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; }
영속성 컨텍스트:
1차 캐시:
- 같은 트랜잭션 내 id 같으면 같은 객체 반환
- 두 번째 find 는 SQL X (캐시)
→ JDBC 호출 최소화
변경 감지 (Dirty Checking):
객체 수정 시:
1. JPA 가 변경 감지 (영속성 컨텍스트)
2. 트랜잭션 commit 시
3. UPDATE SQL 자동 생성
4. JDBC 로 실행
→ 명시적 UPDATE 불필요
flush:
영속성 컨텍스트 → DB 반영:
- 자동 (트랜잭션 commit 시)
- 또는 명시적 (em.flush())
- SQL 묶음 실행
→ 효율적 (배치)
// 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); }
JPA 의 JDBC 호출 흐름은?
답:
1. 흐름:
JPA 내부:
영속성 컨텍스트:
Dirty Checking:
DataSource 의 역할:
- Connection 제공
- 풀 (HikariCP) 관리
- 자바 표준 인터페이스 (javax.sql)
6주차 학습:
- 6주차 Phase 5 (DataSource 인터페이스)
- 6주차 Phase 4 (Connection Pool)
JPA 의 DataSource 사용:
EntityManagerFactory:
- DataSource 주입 받음
- Connection 필요 시 getConnection() 호출
→ 6주차 DataSource 그대로
흐름:
① JPA 가 SQL 실행 필요
↓
② DataSource.getConnection() 호출
↓
③ HikariCP 풀에서 Connection 빌림
↓
④ JDBC PreparedStatement 실행
↓
⑤ ResultSet 처리
↓
⑥ Connection 반환 (HikariCP 풀로)
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. 모두 연결
# 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;
DataSource 가 JPA 에서 위치는?
답:
1. 역할:
JPA 사용:
HikariCP:
자동:
HikariCP 의 위치:
6주차 학습:
- 가장 빠른 Connection Pool
- Spring Boot 기본
7주차 (JPA):
- 그대로 활용
- JPA 가 DataSource 통해 사용
- 6주차 학습 그대로 통합
풀의 가치 (JPA 에서도):
- Connection 생성 비용 ↓
- 동시 사용자 처리 ↑
- 응답 시간 ↓
- DB 부하 ↓
→ JPA 도 마찬가지
사용 흐름:
1. JPA 가 SQL 실행 필요
2. dataSource.getConnection() 호출
3. HikariCP 풀에서 빌림 (대기 X, 즉시)
4. SQL 실행
5. JPA 가 작업 끝
6. conn.close() 호출 (JPA 내부)
7. HikariCP 가 풀로 반환 (재사용)
# 풀 크기 (운영 환경)
spring:
datasource:
hikari:
maximum-pool-size: 20 # 동시 Connection 최대
minimum-idle: 5 # 최소 유지
connection-timeout: 30000 # 대기 시간 (ms)
idle-timeout: 600000 # 유휴 시간
max-lifetime: 1800000 # 최대 생명 시간
# JPA / JDBC 동일
6주차 ↔ 7주차:
6주차 Phase 4 — Connection Pool:
- HikariCP 도입
- 풀의 가치
- 풀 크기 결정
→ 7주차에서 그대로
→ JPA 가 활용
→ 학습 누적 가치
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주차 = 통합 시너지
HikariCP 는 JPA 에서도 활용되는가?
답:
1. YES:
JPA:
풀 효과:
6주차 학습:
Spring Boot 자동 구성:
spring-boot-starter-data-jpa:
- DataSource 자동 (HikariCP)
- EntityManagerFactory 자동
- TransactionManager 자동
- Spring Data JPA 활성화
→ application.yml 만 설정
자동 생성 빈:
1. DataSource (HikariDataSource)
2. EntityManagerFactory (Hibernate)
3. EntityManager (각 트랜잭션)
4. PlatformTransactionManager
- JpaTransactionManager
5. JpaRepositoryFactory
- Repository 자동 구현
// 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
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
자동 구성의 가치:
Spring Boot 등장 전:
- 수십 줄 XML 설정
- 빈 정의 직접
- 의존성 직접 관리
Spring Boot:
- application.yml 만
- 자동
- 관례 따르기 (Convention over Configuration)
→ 생산성 극대화
# 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 # 운영
Spring Boot 의 자동 구성은?
답:
1. 자동:
자동 빈:
의존성:
설정:
6주차 학습 → 7주차 통합:
6주차 학습한 것:
✅ JDBC (Connection, Statement, ResultSet)
✅ DataSource (인터페이스 추상화)
✅ HikariCP (Connection Pool)
✅ 트랜잭션 ACID
✅ JdbcTemplate
✅ DataSourceTransactionManager
7주차 (JPA) 에서:
- 모두 그대로 활용
- JPA 가 위에 얹힘
- 6주차 = JPA 의 기반
학습 누적 가치:
6주차 단단히 학습 →
7주차 JPA 깊이 이해
6주차 부실 →
7주차 JPA 혼란
→ 6주차가 7주차의 기반
→ 박승제도 6주차부터 차근차근
트러블슈팅:
JPA 문제 발생 시:
- SQL 어떻게 만들어졌나? (show-sql, 6주차 학습)
- Connection 누수? (HikariCP, 6주차)
- 트랜잭션 안 풀림? (ACID, 6주차)
- N+1? (JOIN 이해, 7주차 + 6주차)
→ 6주차 학습이 직접 활용
통합의 아름다움:
자바 진영의 추상화:
- 인터페이스 (JDBC, JPA)
- 구현체 (Driver, Hibernate)
- 표준 (자바 명세)
- 5주차 패턴
학습 누적:
- 각 주차가 독립적이지만
- 위로 갈수록 통합
- 7주차 = 1-6주차의 결정체
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주차 = 모든 학습의 응축
6주차 학습이 그대로 통합되는 의미는?
답:
1. 통합:
누적 가치:
트러블슈팅:
아름다움:
JPA 가 안 보이게 하는 것:
1. SQL 생성
2. Connection 획득 / 반환
3. PreparedStatement 생성
4. ResultSet 처리
5. 객체 ↔ ResultSet 변환
6. 트랜잭션 동기화
7. 영속성 컨텍스트 관리
8. Dirty Checking
9. 캐시 (1차)
10. 객체 그래프 로딩 (Lazy/Eager)
6주차 자원 관리:
JDBC 직접:
- try/catch/finally
- close 들
JdbcTemplate (6주차):
- 자원 관리 자동
JPA (7주차):
- 자원 관리 자동
- + 그 외 모두 자동
→ 추상화 깊어짐
보이는 것만 (개발자):
- @Entity 정의
- Repository 인터페이스
- 비즈니스 로직 (객체 작업)
- @Transactional
나머지 모두 자동
추상화의 양면:
장점:
- 생산성 ↑
- 가독성 ↑
- 비즈니스 집중
단점:
- "마법" 같음
- 내부 모르면 디버깅 ↓
- 성능 튜닝 어려움
- 학습곡선 ↑
→ 내부 이해 필요 (이번 Unit 의 의의)
| Q | 핵심 답변 |
|---|---|
| JPA 위치? | 중간 계층 |
| 4단계? | App/JPA/JDBC/Driver |
| JDBC 대체? | NO, 위에 얹음 |
| HikariCP? | 그대로 활용 |
| 호출 흐름? | App → JPA → JDBC → DB |
| DataSource? | JPA 가 사용 |
| Spring Boot? | 자동 구성 |
| 6주차 통합? | 그대로 |
| 안 보이는 일? | 자원 / 캐시 / 변경 감지 |
| 추상화의 양면? | 장단점 |
답:
답:
답:
답:
답:
1. JPA 의 위치 = 애플리케이션과 JDBC 사이 중간 계층
2. JDBC + JPA 공존
3. Spring Boot 자동 구성
이번 Unit에서 JPA 위치를 봤다면, 다음은 Spring Data JPA + 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 완주
🗂️ 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 · 끝