F-LAB JAVA · 7주차 · Phase 2 · ORM 패러다임
🏆 Phase 2 완주 — ORM 의 본질
이 Unit을 끝내면 다음을 답할 수 있어야 한다.
ORM (Object-Relational Mapping) 은 객체와 관계형 DB 사이의 5가지 미스매치를 프레임워크가 자동 매핑해 객체로만 작업하게 해주는 도구로, 자바의 Hibernate · Python 의 SQLAlchemy · Ruby 의 ActiveRecord 등이 대표적이며 개발 속도가 빨라지지만 SQL 을 완전히 대체하진 않고 학습곡선 · N+1 · 튜닝 같은 단점도 있다.
ORM (Object-Relational Mapping) 은 객체와 관계형 DB 사이의 매핑을 자동화 하는 프레임워크다.
동작 방식은 — 객체는 객체대로 설계하고 DB 는 DB 대로 설계하면, ORM 프레임워크가 중간에서 5가지 미스매치 (모델링/상속/연관/식별/타입) 를 자동으로 변환 한다.
효과는 — (1) 매핑 코드 자동 생성, (2) 개발 속도 ↑, (3) DB 변경 시 코드 변경 ↓ (Dialect), (4) 객체지향적 코드 유지.
대표 ORM 은 — 자바의 Hibernate (JPA 구현체) · EclipseLink, Python 의 SQLAlchemy · Django ORM, Ruby 의 ActiveRecord, C# 의 Entity Framework — 모든 주요 언어가 ORM 을 가진다.
단 ORM 도 만능은 아니다 — SQL 을 완전히 대체하지 않으며 (복잡 통계는 네이티브 쿼리), 단점으로 (1) 학습곡선, (2) N+1 문제, (3) 성능 튜닝 어려움 이 있어 6주차 JdbcTemplate (SQL Mapper) 과 적절히 혼용한다.
ORM = 자동 번역기:
상황:
- 한국어 회사 (객체) ↔ 영어 회사 (DB)
- 매번 손으로 번역 = 고통
ORM (자동 번역기):
- 한국어 입력 → 영어 자동 변환
- 양방향
- 5가지 미스매치 모두
자동 매핑:
- "이 객체 저장해" → INSERT SQL 자동
- "이 객체 가져와" → SELECT SQL 자동
- 사람은 객체로만
대중적 ORM (각 언어):
- Java: Hibernate
- Python: SQLAlchemy
- Ruby: ActiveRecord
- C#: Entity Framework
→ 모든 언어 ORM
번역기의 한계:
- 복잡 문장 어색 (네이티브 SQL 필요)
- 학습곡선 (배워야)
- N+1 (비효율 번역)
- 튜닝 어려움
자바 진영:
- JPA = 인터페이스 (표준)
- Hibernate = 구현체 (실제)
- "JPA 명세 + Hibernate 구현"
→ ORM = 자동 매핑 프레임워크, 모든 언어에 존재, 만능은 아니다.
1. ORM 정의
2. 동작 방식 (중간 매핑)
3. ORM 효과
4. 대중적 ORM
5. 자바 진영 (Hibernate / JPA)
6. SQL 완전 대체 X
7. ORM 단점 3가지
8. N+1 문제
9. ORM vs SQL Mapper
ORM (Object-Relational Mapping):
객체 (Object) 와
관계형 DB (Relational) 사이의
매핑 (Mapping) 을 자동화하는 프레임워크
→ 5가지 미스매치 (Unit 2.1) 해결
"Mapping":
객체 ↔ DB 행 매핑:
- 객체의 필드 ↔ 테이블의 컬럼
- 객체의 참조 ↔ FK
- 객체의 컬렉션 ↔ 별도 테이블
- 객체의 상속 ↔ 3가지 전략
→ 양방향 자동
패러다임:
객체:
- 객체대로 설계
- 도메인 모델
- OOP 원칙
DB:
- DB 대로 설계
- 정규화
- SQL 표준
ORM 이 중간:
- 객체 ↔ DB 자동
- 양쪽 그대로
ORM 정의 (ILIC)
ILIC 의 객체:
class Shipment {
Long id;
String blNo;
Customer customer;
List<ShipmentItem> items;
BigDecimal weight;
}
ILIC 의 DB:
CREATE TABLE shipments (id, bl_no, customer_id, weight);
CREATE TABLE customers (id, name);
CREATE TABLE shipment_items (id, shipment_id, ...);
ORM (Hibernate) 의 역할:
- shipment.save() → INSERT 자동
- findById(1) → SELECT + 객체 변환
- shipment.getItems() → JOIN 또는 별도 SELECT
- 양방향 매핑
→ 개발자는 객체로만 작업
ORM (Object-Relational Mapping) 의 정의는?
답:
1. ORM:
자동:
패러다임:
목적:
ORM 의 위치:
┌─────────────────────────────────┐
│ Application (객체 코드) │
└────────────┬────────────────────┘
│ ORM API
↓
┌─────────────────────────────────┐
│ ORM (Hibernate) │ ← 매핑
└────────────┬────────────────────┘
│ JDBC API
↓
┌─────────────────────────────────┐
│ JDBC │
└────────────┬────────────────────┘
↓
┌─────────────────────────────────┐
│ DB │
└─────────────────────────────────┘
양방향:
객체 → DB:
- save(객체)
- ORM: 객체 → SQL (INSERT/UPDATE)
- JDBC 로 실행
DB → 객체:
- findById(id)
- ORM: SELECT 실행
- ResultSet → 객체
→ 자동 변환
메타데이터 기반:
어노테이션 / XML:
- @Entity, @Id, @Column
- 매핑 정보 명시
ORM 이 읽어서:
- SQL 생성
- 객체 ↔ DB 변환
// 객체 정의 (메타데이터)
@Entity
@Table(name = "shipments")
public class Shipment {
@Id
private Long id;
@Column(name = "bl_no")
private String blNo;
}
// 사용
Shipment s = new Shipment();
s.setBlNo("BL001");
em.persist(s);
// ORM 이 자동:
// INSERT INTO shipments (bl_no) VALUES ('BL001');
Shipment found = em.find(Shipment.class, 1L);
// ORM 이 자동:
// SELECT * FROM shipments WHERE id = 1;
// ResultSet → Shipment 객체
class EntityManager {
void persist(Object o) {}
<T> T find(Class<T> c, Object id) { return null; }
}
EntityManager em;
// ORM 동작 (ILIC, JPA 사용)
@Entity
@Table(name = "shipments")
public class Shipment {
@Id
@GeneratedValue
private Long id;
private String blNo;
@ManyToOne
@JoinColumn(name = "customer_id")
private Customer customer;
@OneToMany(mappedBy = "shipment")
private List<ShipmentItem> items;
}
// 사용 (객체로만)
Shipment s = new Shipment();
s.setBlNo("BL001");
s.setCustomer(customer); // 참조
s.getItems().add(item); // 컬렉션
shipmentRepository.save(s);
// JPA 가:
// 1. shipments INSERT
// 2. customer_id 자동 (FK)
// 3. shipment_items 별도 INSERT
Shipment found = shipmentRepository.findById(1L).orElseThrow();
found.getCustomer().getName(); // 객체 그래프 자동
found.getItems(); // 컬렉션 자동
class Customer { String getName() { return null; } }
class ShipmentItem {}
ShipmentRepository shipmentRepository;
interface ShipmentRepository {
Shipment save(Shipment s);
java.util.Optional<Shipment> findById(Long id);
}
class Shipment {
void setBlNo(String s) {}
void setCustomer(Customer c) {}
java.util.List<ShipmentItem> getItems() { return null; }
Customer getCustomer() { return null; }
}
ORM 의 동작 방식 (중간 매핑) 은?
답:
1. 위치:
양방향:
메타데이터:
자동:
매핑 코드 자동:
ORM 없으면:
- 매 메서드마다 SQL + 매핑
- 보일러플레이트
- 시간 낭비
ORM 있으면:
- 어노테이션 한 번
- SQL 자동
- 매핑 자동
→ 보일러플레이트 ↓
개발 속도:
CRUD 작성 시간:
- JDBC 직접: 30분
- JdbcTemplate: 10분
- JPA + Spring Data: 1분
(Repository 인터페이스만)
→ 압도적
DB 변경:
MySQL → PostgreSQL 변경 시:
- JDBC 직접: SQL 문법 차이 (LIMIT/AUTO_INCREMENT 등) 수정
- JdbcTemplate: 동일
- JPA: Dialect 만 변경 (보통 자동)
→ DB 무관성
객체지향 유지:
ORM 없으면:
- 객체에 DB 코드 섞임
- SoC 깨짐
- 도메인 로직 흐려짐
ORM 있으면:
- 객체는 객체로
- DB 무관
- OOP 원칙
→ 코드 품질 ↑
생산성:
비즈니스 로직 집중:
- 매핑/SQL 신경 X
- 도메인에 집중
- 시간 절약
→ 모던 백엔드 표준
ORM 효과 (ILIC)
ILIC 가 ORM (JPA) 사용으로:
1. 매핑 코드 ↓
- 102 테이블 × 평균 10 메서드 = 1020 매핑 코드
- JPA 로 어노테이션 + Repository
- 코드 70% 감소
2. 개발 속도 ↑
- 새 테이블 추가:
- JDBC: 100 줄
- JPA: 20 줄
3. DB 변경 가능
- 만약 MySQL → PostgreSQL
- Dialect 변경만
- 대부분 코드 그대로
4. 객체지향 유지
- Shipment, Customer 등 도메인 객체
- DB 코드 X
- 깔끔
5. 생산성
- 박승제 같은 풀스택 개발자
- 102 테이블도 관리 가능
- JPA 가 있어서
→ ILIC = JPA 주력, JdbcTemplate 보조
ORM 의 효과는?
답:
1. 매핑 자동:
개발 속도:
DB 무관:
객체지향:
자바 ORM:
- Hibernate (가장 대중)
- EclipseLink
- DataNucleus
- OpenJPA
→ Hibernate 가 사실상 표준
Python ORM:
- SQLAlchemy (강력)
- Django ORM (Django 통합)
- Peewee (가벼움)
- Tortoise ORM (async)
→ SQLAlchemy 가 가장 인기
Ruby ORM:
- ActiveRecord (Ruby on Rails)
- 이름 자체가 패턴
- Rails 와 통합
- 매우 직관적
→ Rails = ActiveRecord
C# ORM:
- Entity Framework
- Microsoft 공식
- LINQ 통합
- Entity Framework Core
- 크로스 플랫폼
- Dapper (Micro ORM)
→ EF 가 표준
기타:
PHP: Doctrine, Eloquent
Go: GORM, Ent
Node.js: Sequelize, TypeORM, Prisma
Rust: Diesel, SeaORM
Kotlin: Exposed, Hibernate
→ 모든 주요 언어 ORM
공통 특징:
- 객체 ↔ DB 자동 매핑
- 어노테이션/데코레이터/매크로
- CRUD 자동
- 관계 (1:1, 1:N, N:M) 매핑
- 쿼리 빌더
→ "객체로 작업" 표준
ILIC 의 ORM 선택
ILIC = 자바 + Spring Boot
→ Hibernate (JPA 구현체)
→ Spring Data JPA 추가 (편의)
→ Querydsl (복잡 쿼리)
실무 조합:
Spring Data JPA + Querydsl + JPA + Hibernate
주력:
- Hibernate (실제 매핑)
- Spring Data JPA (Repository 자동)
- Querydsl (동적/복잡 쿼리)
보조:
- JdbcTemplate (네이티브 SQL 필요 시)
대중적 ORM 라이브러리들은?
답:
1. 자바:
Python:
Ruby:
C#:
JPA 와 Hibernate:
JPA (Java Persistence API):
- 자바 ORM 표준 인터페이스
- 명세 (Spec)
- 구현체 X
Hibernate:
- JPA 구현체
- 가장 인기
- 실제 동작
→ "인터페이스 + 구현체"
JPA 의 역할:
- 표준 인터페이스
- 어노테이션 정의
(@Entity, @Id, @Column, ...)
- 메서드 정의
(persist, find, merge, ...)
- 모든 구현체가 따름
→ DI/DataSource 정신 (인터페이스)
Hibernate 의 역할:
- JPA 인터페이스 구현
- 실제 SQL 생성
- 캐싱
- Dirty Checking
- Lazy Loading
- + Hibernate 고유 기능
→ JPA + 추가
관계:
Application
↓ (의존)
JPA (인터페이스, javax.persistence.*)
↑ (구현)
Hibernate (구현체)
↓
JDBC → DB
→ 5주차 인터페이스 패턴
→ 6주차 DataSource 와 같은 정신
다른 구현체:
JPA 구현체:
- Hibernate ★★★ (압도적)
- EclipseLink (Eclipse 공식)
- DataNucleus
- OpenJPA
→ 인터페이스 의존, 구현체 교체 가능 (이론상)
→ 실무는 Hibernate
Spring Data JPA:
JPA 의 또 다른 추상화:
- Repository 인터페이스 자동 구현
- 메서드 이름 → SQL 자동
- findByXxx, deleteByYyy
→ JPA 위의 또 다른 레이어
→ 다음 Phase 3
ILIC 의 JPA 스택
ILIC:
- Spring Boot 3
- Spring Data JPA (의존성)
→ 자동으로 Hibernate (JPA 구현체)
→ 자동으로 JPA
→ 자동으로 JDBC + HikariCP
스택:
Application
↓
Spring Data JPA (메서드 이름 자동 쿼리)
↓
JPA (인터페이스)
↓
Hibernate (실제 구현, SQL 생성)
↓
JDBC (6주차)
↓
HikariCP (Connection Pool, 6주차)
↓
MySQL
→ 깊은 추상화 스택
자바의 ORM (Hibernate/JPA) 은?
답:
1. JPA:
Hibernate:
관계:
Spring Data:
ORM 의 한계:
- 단순 CRUD: ORM 잘 함
- 복잡 쿼리: 어려움
- 동적 쿼리
- 복잡 집계
- 윈도우 함수
- DB 별 특수 기능
→ SQL 도 알아야
// 네이티브 쿼리 (JPA)
@Query(value = """
SELECT s.*, c.name
FROM shipments s
JOIN customers c ON s.customer_id = c.id
WHERE EXISTS (
SELECT 1 FROM freights f
WHERE f.shipment_id = s.id
AND f.amount > (
SELECT AVG(amount) FROM freights
)
)
""", nativeQuery = true)
List<Object[]> findHighValueShipments();
// JPA 가 못 자동 생성
// SQL 직접
class Object {}
// JPQL (Java Persistence Query Language)
// - 객체 지향 쿼리
// - 테이블 X, 엔티티 사용
@Query("""
SELECT s FROM Shipment s
JOIN s.customer c
WHERE c.region = :region
""")
List<Shipment> findByRegion(@Param("region") String region);
// JPQL → SQL 변환
// 객체 그래프 활용
class Shipment {}
@interface Param { String value(); }
// Querydsl (타입 안전 쿼리 빌더)
List<Shipment> result = queryFactory
.selectFrom(shipment)
.join(shipment.customer, customer)
.where(
shipment.weight.gt(new BigDecimal("100"))
.and(customer.region.eq("Asia"))
)
.fetch();
// 컴파일 시점 타입 체크
// 동적 쿼리 강력
혼용:
- 단순 CRUD: JPA Repository
- 객체 그래프: JPQL
- 복잡 동적: Querydsl
- 네이티브: @Query(native)
- 매우 복잡: JdbcTemplate (6주차)
→ 도구 적절히
// ILIC 의 혼용 패턴
// 1. 단순 CRUD: Spring Data JPA
interface ShipmentRepository extends JpaRepository<Shipment, Long> {
List<Shipment> findByStatus(String status);
// 자동 SQL: WHERE status = ?
}
// 2. 객체 그래프: JPQL
@Query("""
SELECT s FROM Shipment s
JOIN FETCH s.customer
WHERE s.status = :status
""")
List<Shipment> findWithCustomer(@Param("status") String status);
// 3. 동적: Querydsl
QShipment s = QShipment.shipment;
BooleanBuilder where = new BooleanBuilder();
if (status != null) where.and(s.status.eq(status));
if (minWeight != null) where.and(s.weight.gt(minWeight));
queryFactory.selectFrom(s).where(where).fetch();
// 4. 복잡 통계: JdbcTemplate
jdbcTemplate.queryForList("""
SELECT region, COUNT(*), AVG(amount),
PERCENT_RANK() OVER (PARTITION BY region ORDER BY amount)
FROM shipment_view
GROUP BY region
""");
// → 각자 적합한 도구
class Shipment {}
class QShipment { static QShipment shipment = new QShipment(); }
class BooleanBuilder { BooleanBuilder and(Object o) { return this; } }
ORM 이 SQL 을 완전히 대체하는가?
답:
1. NO:
JPQL:
Querydsl:
혼용:
학습곡선:
ORM 익숙해지기:
- 어노테이션 (수십 개)
- 영속성 컨텍스트
- Lazy Loading
- 트랜잭션 통합
- 캐시 동작
- 3-6개월 정도
- 깊은 이해 더 오래
→ 진입 장벽 ↑
N+1 문제:
목록 조회 1 + 각 항목별 1 + ... = 1+N
대량 데이터:
- 1000 고객 + 각자 배송
- 1001 쿼리 발생
- 성능 폭망
→ 가장 흔한 함정
성능 튜닝:
ORM 추상화의 비용:
- 어떤 SQL 생성?
- 왜 느린가?
- 인덱스 활용?
- Fetch 전략?
- SQL 직접보다 어려움
- JPA 의 내부 이해 필요
- 로깅으로 SQL 확인
→ 깊은 이해 필요
다른 단점들:
- 복잡 쿼리 표현 어려움
- 캐시 일관성 (1차/2차)
- 마이그레이션 의존
- 라이브러리 의존성
단점 해결:
학습곡선:
- 점진적 학습
- 책/강의
N+1:
- fetch join
- @EntityGraph
- Batch fetch
성능 튜닝:
- show-sql / p6spy
- JPA Buddy 등 도구
- 실무 경험
ILIC 의 ORM 단점 대응
학습곡선:
- 박승제도 충분히 학습 후 사용
- 팀원도 점진적
- 6주차 (JDBC/JdbcTemplate) 가 기반
N+1:
- Spring Data JPA + fetch join
- @EntityGraph
- 로깅 (spring.jpa.show-sql)
- 코드 리뷰에서 체크
성능 튜닝:
- show-sql + format-sql
- p6spy 또는 datasource-proxy
- 슬로우 쿼리 모니터링
- 인덱스 / EXPLAIN
- 복잡 쿼리는 JdbcTemplate 보완
→ JPA 활용 + 도구 + 경험
ORM 의 단점 3가지는?
답:
1. 학습곡선:
N+1:
튜닝 어려움:
해결:
N+1 문제:
목록 1 쿼리 + 각 항목별 N 쿼리:
1 + N 쿼리
ORM 의 함정:
- 자동 매핑이 너무 친절
- 무심코 발생
// N+1 발생
List<Customer> customers = customerRepository.findAll(); // 1 쿼리
// SELECT * FROM customers;
for (Customer c : customers) {
System.out.println(c.getShipments().size());
// → 각자 SELECT * FROM shipments WHERE customer_id = ?;
// → N 쿼리
}
// 총: 1 + N (고객 1000명이면 1001 쿼리!)
class Customer { java.util.List<?> getShipments() { return null; } }
CustomerRepository customerRepository;
interface CustomerRepository { java.util.List<Customer> findAll(); }
// fetch join (한 번에)
@Query("""
SELECT c FROM Customer c
LEFT JOIN FETCH c.shipments
""")
List<Customer> findAllWithShipments();
// 1 쿼리 (LEFT JOIN)
// SELECT c.*, s.* FROM customers c LEFT JOIN shipments s ON ...
class Customer {}
@interface Query { String value(); }
// @EntityGraph (Spring Data JPA)
@EntityGraph(attributePaths = {"shipments"})
List<Customer> findAll();
// 자동 fetch join
class Customer {}
@interface EntityGraph { String[] attributePaths(); }
# application.yml
spring:
jpa:
properties:
hibernate:
default_batch_fetch_size: 100
# → IN 절로 100 개씩 한 번에
# → 1 + N/100 쿼리
진단:
show-sql:
- SQL 로그 확인
- 의외로 많이 발생
p6spy:
- 실제 SQL + 시간
- 더 자세
슬로우 쿼리:
- DB 로그
- 운영 모니터링
→ "왜 이렇게 많이?" 가 N+1 신호
// ILIC 의 N+1 대응
// 위험 코드
List<Customer> customers = customerRepository.findAll();
customers.forEach(c -> {
log.info("고객 {}: 배송 {} 건", c.getName(), c.getShipments().size());
// 각 고객마다 SELECT
});
// 해결 1: fetch join
@Query("""
SELECT c FROM Customer c
LEFT JOIN FETCH c.shipments
""")
List<Customer> findAllWithShipments();
// 해결 2: 별도 조회
List<Customer> customers = customerRepository.findAll();
List<Long> customerIds = customers.stream().map(Customer::getId).toList();
Map<Long, List<Shipment>> shipmentMap = shipmentRepository
.findByCustomerIdIn(customerIds)
.stream()
.collect(Collectors.groupingBy(s -> s.getCustomer().getId()));
// 1 + 1 쿼리
// 해결 3: 배치 fetch
// application.yml 설정만으로 자동
// ILIC 의 표준:
// - default_batch_fetch_size: 100
// - + 필요 시 fetch join
class Customer {
Long getId() { return null; }
String getName() { return null; }
java.util.List<Shipment> getShipments() { return null; }
}
class Shipment {
Customer getCustomer() { return null; }
}
org.slf4j.Logger log;
ShipmentRepository shipmentRepository;
interface ShipmentRepository {
java.util.List<Shipment> findByCustomerIdIn(java.util.List<Long> ids);
}
CustomerRepository customerRepository;
N+1 문제는?
답:
1. N+1:
시나리오:
해결:
진단:
| 항목 | SQL Mapper (JdbcTemplate, MyBatis) | ORM (JPA, Hibernate) |
|---|---|---|
| SQL 작성 | 개발자 직접 | ORM 이 자동 생성 |
| 매핑 | RowMapper 수동 | 어노테이션 자동 |
| 객체 그래프 | 수동 처리 | 자동 (Lazy Loading) |
| 학습 곡선 | 낮음 | 높음 |
| 복잡 쿼리 | 자유 | 어려움 (네이티브) |
| 캐시 | 직접 구현 | 1차/2차 자동 |
| Dirty Checking | X | 자동 |
| 변경 감지 | UPDATE 명시 | 자동 |
SQL Mapper 강점:
- SQL 직접 (자유)
- 복잡 쿼리 강력
- 학습 ↓
- 성능 예측 쉬움
- DB 특수 기능 활용
→ 분석/리포트/통계에 강함
ORM 강점:
- 객체로 작업
- CRUD 자동
- 객체 그래프
- 영속성 컨텍스트
- 변경 자동 감지
→ 도메인 로직에 강함
선택 기준:
CRUD 위주 / 도메인 모델:
- ORM (JPA)
복잡 쿼리 / 분석 / 통계:
- SQL Mapper (JdbcTemplate)
- 또는 JPA + 네이티브 쿼리
실무:
- JPA 주력 + JdbcTemplate 보조
- 적절히 혼용
6주차 ↔ 7주차:
6주차:
- JdbcTemplate (SQL Mapper)
- SQL 직접
- 매핑 (RowMapper)
7주차:
- JPA (ORM)
- SQL 자동
- 매핑 (어노테이션)
→ 같은 문제 다른 추상화 수준
→ 둘 다 알아야
// ILIC 의 SQL Mapper + ORM 혼용
// 1. 단순 CRUD: JPA (주력)
interface ShipmentRepository extends JpaRepository<Shipment, Long> {
List<Shipment> findByStatus(String status);
}
// 2. 도메인 그래프: JPA
@Entity
class Shipment {
@OneToMany List<ShipmentItem> items;
}
Shipment s = repo.findById(1L);
s.getItems(); // 자동
// 3. 복잡 통계: JdbcTemplate (보조)
public List<Map<String, Object>> complexStats() {
return jdbcTemplate.queryForList("""
WITH ranked AS (
SELECT region, amount,
RANK() OVER (PARTITION BY region ORDER BY amount DESC) AS rk
FROM shipments
)
SELECT * FROM ranked WHERE rk <= 5
""");
// 윈도우 함수 + CTE
// JPA 로 표현 어려움
}
// → 도구 적절히 혼용
// → ILIC 의 표준 패턴
class Shipment {
java.util.List<ShipmentItem> getItems() { return null; }
}
class ShipmentItem {}
interface JpaRepository<T, ID> {
java.util.Optional<T> findById(ID id);
}
class JdbcTemplate {
java.util.List<java.util.Map<String, Object>> queryForList(String s) { return null; }
}
JdbcTemplate jdbcTemplate;
ShipmentRepository repo;
| Q | 핵심 답변 |
|---|---|
| ORM? | 객체 ↔ RDB 매핑 |
| 효과? | 자동 / 속도 / DB 무관 |
| 대중적? | Hibernate/SQLAlchemy/AR |
| JPA vs Hibernate? | 인터페이스 vs 구현 |
| SQL 대체? | NO (복잡은 직접) |
| 단점? | 학습/N+1/튜닝 |
| N+1? | 1+N 쿼리 |
| vs SQL Mapper? | 추상화 수준 |
| Spring Data? | JPA 위 추상화 |
| 혼용? | 적절히 |
답:
답:
답:
답:
답:
1. ORM 정의와 효과
2. 대중적 ORM
3. 만능 아님
🔄 Phase 2 — ORM 패러다임
✅ Unit 2.1 객체-관계 미스매치
✅ Unit 2.2 ORM 의 정의와 효과 ← 여기, Phase 2 완주
→ 5가지 미스매치 이해
→ ORM 의 본질 이해
→ Phase 3 (JPA 입문) 의 기반
🌱 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 — SQL JOIN (5)
✅ Phase 2 — ORM 패러다임 (2) ← 완주
⏭ Phase 3 — JPA 입문 (4)
⏭ Phase 4 — JPA 엔티티 매핑 (5)
🔄 Part B — 트랜잭션 추상화의 진화
⏭ Phase 5 (2)
⏭ Phase 6 (3)
⏭ Phase 7 (3)
총: 7/24 Unit
🏆 Phase 2 완주 — ORM 패러다임