F-LAB JAVA · 6주차 · Phase 7 · JdbcTemplate (반복 제거)
🏆🏆 Phase 7 완주 + 6주차 전체 완주! — 5주차 디자인 패턴의 결정체
이 Unit을 끝내면 다음을 답할 수 있어야 한다.
JdbcTemplate 은 5주차에서 배운 모든 디자인 패턴과 원칙 — 관심사 분리·템플릿 메소드 패턴·전략 패턴·OCP·DI — 의 집약체이며, 거기에 3주차의 람다·함수형 인터페이스까지 결합되어 가장 간결한 사용법을 제공하는 자바 진영 OOP 의 결정체다.
JdbcTemplate 의 구조적 의미는 6주차에서 본 모든 학습이 한 클래스에 녹아 있다는 점이다.
(1) 관심사 분리 — 인프라 (자원 관리/예외 처리) 와 비즈니스 (SQL/매핑) 분리, (2) 템플릿 메소드 패턴 — 변하지 않는 흐름을 템플릿에, (3) 전략 패턴 — 변하는 부분을 RowMapper 등 전략으로, (4) OCP — 새 쿼리 = 새 람다, 기존 코드 변경 X, (5) DI — DataSource 외부 주입.
거기에 3주차의 람다·함수형 인터페이스 가 결합되어 RowMapper·PreparedStatementSetter 가 람다 한 줄로 표현 가능해, JDBC 직접 20+ 줄 → JdbcTemplate 3-5 줄의 가장 간결한 사용법이 가능하다.
JdbcTemplate 은 곧 자바 진영 OOP 의 결정체 — 좋은 라이브러리란 이렇게 디자인 패턴과 원칙들이 자연스럽게 녹아있는 것이며, 이를 학습하는 것이 곧 OOP 와 SOLID 의 실제를 배우는 길이다.
JdbcTemplate = 6주차 학습의 결정체:
5주차 디자인 패턴:
- 관심사 분리 → JdbcTemplate (인프라 ↔ 비즈니스)
- 템플릿 메소드 → JdbcTemplate (흐름) + 전략 (매핑)
- 전략 패턴 → RowMapper 외부 주입
- OCP → 새 쿼리 추가만 (변경 X)
- DI → DataSource 받음
3주차 람다 + 함수형:
- RowMapper = 함수형 인터페이스
- 람다 한 줄로 매핑
6주차 다른 Phase:
- Phase 3 (JDBC): JdbcTemplate 이 추상화
- Phase 4 (Connection Pool): JdbcTemplate 이 DataSource 통해
- Phase 5 (DataSource): JdbcTemplate 이 의존
- Phase 6 (트랜잭션): JdbcTemplate 이 협력
결정체:
- 모든 학습이 한 곳에
- "이게 OOP 다"
- 좋은 라이브러리 = 좋은 OOP
마지막 단계:
- 종합 졸업 시험 25문항
- 6주차 전체 검증
→ JdbcTemplate = 6주차 모든 학습의 집약 + 3주차 람다 + 5주차 디자인 패턴.
1. 관심사 분리
2. 템플릿 메소드 패턴
3. 전략 패턴
4. OCP 달성
5. DI 적용
6. 함수형 인터페이스 결합
7. JdbcTemplate = OOP 결정체
8. 6주차 전체 종합
9. 🎓 종합 졸업 시험 25 문항
관심사 분리 (Separation of Concerns):
서로 다른 역할:
- 분리해서 관리
- 한 곳은 한 가지
→ 5주차 단골 원칙
JdbcTemplate 의 분리:
인프라 (JdbcTemplate 안):
- Connection 획득/해제
- PreparedStatement 생성/해제
- ResultSet 처리
- 예외 변환
비즈니스 (개발자):
- SQL
- 파라미터
- 매핑
효과:
- 비즈니스 로직 가독성 ↑
- 인프라 코드 안 봄 (숨김)
- 각자 발전 가능
- 유지보수 ↑
// 관심사 분리 (ILIC)
@Repository
public class ShipmentDao {
private final JdbcTemplate jdbcTemplate;
public ShipmentDao(JdbcTemplate jt) { this.jdbcTemplate = jt; }
// 개발자는 비즈니스만:
public Shipment get(Long id) {
return jdbcTemplate.queryForObject(
"select * from shipments where id = ?", // 비즈니스 (SQL)
(rs, n) -> { // 비즈니스 (매핑)
Shipment s = new Shipment();
s.setId(rs.getLong("id"));
return s;
},
id // 비즈니스 (파라미터)
);
}
// 인프라는 JdbcTemplate 안 (안 보임):
// - Connection 풀에서 빌림
// - PreparedStatement 생성
// - 자원 해제
// - 예외 변환
}
class Shipment { void setId(Long id) {} }
class JdbcTemplate {
<T> T queryForObject(String s, RowMapper<T> r, Object... a) { return null; }
interface RowMapper<T> { T mapRow(ResultSet rs, int n) throws SQLException; }
}
관심사 분리는?
답:
1. SoC:
분리:
효과:
5주차:
템플릿 메소드 패턴:
부모 (템플릿):
- 변하지 않는 흐름
- 알고리즘 골격
자식 (구체):
- 변하는 부분 (오버라이드)
JdbcTemplate 적용:
템플릿 (JdbcTemplate):
- Connection 획득 (1)
- PreparedStatement 생성 (2)
- 변하는 부분 호출 (3)
- 결과 처리 (4)
- 자원 해제 (5)
변하는 부분 (전략으로):
- 3 단계가 외부에서
이름 "Template":
- 5주차 템플릿 메소드 패턴
- 이름 자체가 패턴 명시
- Spring 개발자의 의도
// 템플릿 메소드 (개념)
// 변하지 않는 흐름 (JdbcTemplate 안)
abstract class QueryTemplate<T> {
public T execute() throws SQLException {
// 변하지 않는 단계:
Connection conn = getConnection(); // 1
try {
PreparedStatement ps = createStatement(conn); // 2
try {
setParameters(ps); // ← 변하는 (자식)
ResultSet rs = ps.executeQuery(); // 3
try {
return mapResult(rs); // ← 변하는 (자식)
} finally {
rs.close(); // 4
}
} finally {
ps.close(); // 4
}
} finally {
conn.close(); // 5
}
}
protected abstract Connection getConnection() throws SQLException;
protected abstract PreparedStatement createStatement(Connection c) throws SQLException;
protected abstract void setParameters(PreparedStatement ps) throws SQLException;
protected abstract T mapResult(ResultSet rs) throws SQLException;
}
// → JdbcTemplate 의 정신
// (실제는 콜백/전략 패턴으로 구현)
템플릿 메소드 패턴의 적용은?
답:
1. 템플릿 메소드:
적용:
이름:
변하는:
전략 패턴:
컨텍스트:
- 변하지 않는 흐름
전략 (인터페이스):
- 변하는 부분
- 외부 주입 (생성자/메서드 인자)
→ 템플릿 메소드의 더 유연한 버전
JdbcTemplate 의 전략들:
- PreparedStatementCreator
- PreparedStatementSetter
- RowMapper
- RowCallbackHandler
- ResultSetExtractor
- BatchPreparedStatementSetter
- ...
→ 각자 변하는 부분 담당
메서드 인자:
jdbcTemplate.query(
sql, // 변하는 (SQL)
ps -> ..., // 전략 (파라미터)
(rs, n) -> ... // 전략 (매핑)
)
→ 호출마다 다른 전략
인터페이스 + 람다:
RowMapper (인터페이스):
- 전통적 객체
람다:
- 함수형 (3주차)
- 더 간결
→ 둘 다 가능
// 전략 패턴 (ILIC)
@Repository
public class ShipmentDao {
private final JdbcTemplate jdbcTemplate;
public ShipmentDao(JdbcTemplate jt) { this.jdbcTemplate = jt; }
// 다양한 RowMapper 전략
private final RowMapper<Shipment> fullMapper = (rs, n) -> {
Shipment s = new Shipment();
// 모든 필드
return s;
};
private final RowMapper<Shipment> summaryMapper = (rs, n) -> {
Shipment s = new Shipment();
// 요약 필드
return s;
};
// 같은 JdbcTemplate (컨텍스트), 다른 전략 (RowMapper)
public List<Shipment> findAllFull() {
return jdbcTemplate.query("select * from shipments", fullMapper);
}
public List<Shipment> findAllSummary() {
return jdbcTemplate.query("select id, bl_no from shipments", summaryMapper);
}
// 5주차 전략 패턴의 살아있는 사례
}
class Shipment {}
class JdbcTemplate {
<T> java.util.List<T> query(String s, RowMapper<T> r) { return null; }
}
interface RowMapper<T> { T mapRow(ResultSet rs, int n) throws SQLException; }
전략 패턴의 적용은?
답:
1. 전략 패턴:
JdbcTemplate:
메서드 인자:
람다:
OCP (개방-폐쇄 원칙):
- 확장 열림 (Open)
- 변경 닫힘 (Closed)
새 기능: 추가
기존 코드: 변경 X
JdbcTemplate 의 OCP:
새 쿼리 추가:
- 새 메서드 + 새 람다
- JdbcTemplate 코드 변경 X (닫힘 ✅)
새 매핑 방식:
- 새 RowMapper 구현
- JdbcTemplate 코드 변경 X
새 DB 지원:
- DataSource 만 다르게
- JdbcTemplate 코드 변경 X
→ 모든 면에서 OCP
// 확장: 새 쿼리 (코드 변경 X)
public class ShipmentDao {
// 기존
public Shipment get(Long id) { /* ... */ return null; }
// 확장 (새 쿼리, JdbcTemplate 변경 X)
public List<Shipment> findByCustomQuery(String customSql) {
return jdbcTemplate.query(customSql, mapper);
}
RowMapper<Shipment> mapper;
JdbcTemplate jdbcTemplate;
}
class Shipment {}
class JdbcTemplate {
<T> java.util.List<T> query(String s, RowMapper<T> r) { return null; }
}
interface RowMapper<T> { T mapRow(ResultSet rs, int n) throws SQLException; }
5주차 정신 실현:
JdbcTemplate:
- SOLID 의 O (OCP)
- 확장 자유
- 변경 안전
→ 5주차 학습의 실제
OCP (ILIC)
ILIC 가 새 비즈니스 요구사항:
- 새 통계 쿼리 (확장)
- JdbcTemplate 코드 변경 X
- 새 메서드 + 새 람다만
새 DB 도입 (예: 분석용 PostgreSQL):
- DataSource 만 다르게
- JdbcTemplate 코드 변경 X
- DAO 코드 변경 X
→ OCP 달성
→ 운영 안정성 ↑
OCP 달성 방식은?
답:
1. OCP:
새 쿼리:
새 매핑:
새 DB:
DI (Dependency Injection):
의존성 외부에서 주입:
- 자기가 만들지 X
- 의존 역전 (DIP)
- 5주차 핵심
JdbcTemplate 의 DI:
의존:
- DataSource (인터페이스)
주입:
- 생성자 (new JdbcTemplate(dataSource))
- 또는 Spring 자동
// Spring Boot 자동 DI
@Repository
public class ShipmentDao {
private final JdbcTemplate jdbcTemplate;
// 생성자 주입 (Spring 자동)
public ShipmentDao(JdbcTemplate jdbcTemplate) {
this.jdbcTemplate = jdbcTemplate;
// Spring:
// 1. HikariDataSource 빈 (자동)
// 2. JdbcTemplate 빈 (DataSource 주입)
// 3. ShipmentDao 에 JdbcTemplate 주입
}
}
class JdbcTemplate {}
의존 그래프:
ShipmentDao
↓ (의존)
JdbcTemplate
↓ (의존)
DataSource (인터페이스)
↑ (구현)
HikariDataSource
→ 모두 추상에 의존 (DIP)
→ 외부 주입 (DI)
// DI 그래프 (ILIC)
// 1. application.yml 설정
// spring.datasource.url, hikari.maximum-pool-size 등
// 2. Spring Boot 자동
// - HikariDataSource 빈 (auto-config)
// - JdbcTemplate 빈 (DataSource 주입)
// 3. ILIC DAO
@Repository
public class ShipmentDao {
private final JdbcTemplate jdbcTemplate;
public ShipmentDao(JdbcTemplate jt) {
this.jdbcTemplate = jt;
}
// Spring 이 주입
}
@Repository
public class BookingDao {
private final JdbcTemplate jdbcTemplate;
public BookingDao(JdbcTemplate jt) {
this.jdbcTemplate = jt;
// 같은 JdbcTemplate 빈 (싱글톤 공유)
}
}
// → 5주차 DI 의 실제 활용
class JdbcTemplate {}
DI 의 적용은?
답:
1. DI:
의존:
Spring Boot:
그래프:
3주차 람다 + 함수형 인터페이스:
- @FunctionalInterface
- 추상 메서드 1개
- 람다 표현
→ Java 8+ 핵심
JdbcTemplate 의 활용:
RowMapper:
- 함수형 인터페이스
- 람다 가능
PreparedStatementSetter:
- 함수형 인터페이스
- 람다 가능
Connection ConnectionCallback:
- 함수형 인터페이스
- 람다 가능
→ 모든 콜백이 함수형
람다의 가치:
- 익명 클래스 → 한 줄
- 가독성 ↑
- 함수형 스타일
- 콜백 표현
→ 3주차 학습의 결실
// 메서드 참조 (3주차)
// 매퍼 메서드를 메서드 참조로
return jdbcTemplate.query(
"select * from shipments",
ShipmentMapper::map // 메서드 참조
);
// 또는 this::method
class ShipmentMapper {
static Shipment map(ResultSet rs, int n) throws SQLException {
return null;
}
}
class Shipment {}
JdbcTemplate jdbcTemplate;
class JdbcTemplate {
<T> java.util.List<T> query(String s, RowMapper<T> r) { return null; }
}
interface RowMapper<T> { T mapRow(ResultSet rs, int n) throws SQLException; }
// 함수형 + JdbcTemplate (ILIC)
@Repository
public class ShipmentDao {
private final JdbcTemplate jdbcTemplate;
public ShipmentDao(JdbcTemplate jt) { this.jdbcTemplate = jt; }
// 함수형 (람다)
public List<Shipment> findAll() {
return jdbcTemplate.query(
"select * from shipments",
(rs, n) -> mapRow(rs) // 람다 + 메서드
);
}
// 메서드 참조
public List<Shipment> findByStatus(String status) {
return jdbcTemplate.query(
"select * from shipments where status = ?",
this::mapRow, // 메서드 참조 (3주차)
status
);
}
private Shipment mapRow(ResultSet rs) throws SQLException {
Shipment s = new Shipment();
s.setId(rs.getLong("id"));
return s;
}
// 가변 인자도 람다 가능
public List<Shipment> findHeavy(BigDecimal min) {
return jdbcTemplate.query(
"select * from shipments where weight > ?",
(rs, n) -> { // 람다 (3주차)
Shipment s = new Shipment();
s.setId(rs.getLong("id"));
return s;
},
min
);
}
}
class Shipment { void setId(Long id) {} }
class JdbcTemplate {
<T> java.util.List<T> query(String s, RowMapper<T> r, Object... a) { return null; }
}
interface RowMapper<T> { T mapRow(ResultSet rs, int n) throws SQLException; }
함수형 인터페이스 (람다) 의 결합은?
답:
1. 함수형 인터페이스:
JdbcTemplate:
람다:
메서드 참조:
JdbcTemplate = 모든 학습 결합:
3주차:
- 함수형 인터페이스
- 람다
- 메서드 참조
5주차:
- 관심사 분리
- 템플릿 메소드 패턴
- 전략 패턴
- DI
- OCP / DIP
6주차:
- JDBC (Phase 3)
- Connection Pool (Phase 4)
- DataSource (Phase 5)
- 트랜잭션 (Phase 6)
- JdbcTemplate (Phase 7)
좋은 라이브러리 = 좋은 OOP:
Spring 의 JdbcTemplate:
- 패턴 자연스럽게
- 사용은 간결
- 내부는 정교
→ 라이브러리에서 OOP 배움
6주차 학습의 정점:
JdbcTemplate:
- 모든 학습이 한 곳
- OOP 의 실제
- 면접 단골
→ 6주차의 결승선
5주차 ↔ 6주차:
5주차 (이론/패턴):
- 관심사 분리
- 디자인 패턴
- SOLID
6주차 (실제):
- JDBC → 추상화 (DataSource)
- 트랜잭션 (ACID)
- JdbcTemplate (집약체)
→ 이론과 실제의 만남
// JdbcTemplate 의 모든 의미 (ILIC)
@Repository
public class ShipmentDao {
private final JdbcTemplate jdbcTemplate;
// 5주차 DI
public ShipmentDao(JdbcTemplate jdbcTemplate) {
this.jdbcTemplate = jdbcTemplate;
}
public Shipment get(Long id) {
return jdbcTemplate.queryForObject(
// 6주차 Phase 3 (JDBC SQL)
"select * from shipments where id = ?",
// 3주차 람다 + 5주차 전략 패턴 (RowMapper)
(rs, n) -> {
Shipment s = new Shipment();
s.setId(rs.getLong("id"));
return s;
},
id
);
// 내부:
// - 6주차 Phase 4 (Connection Pool 에서 빌림)
// - 6주차 Phase 5 (DataSource 인터페이스)
// - 6주차 Phase 6 (트랜잭션 @Transactional 협력)
// - 5주차 템플릿 메소드 (변하지 않는 흐름)
// - 5주차 관심사 분리 (인프라/비즈니스)
}
}
// → ILIC 의 DB 접근 = 모든 학습의 결합
class Shipment { void setId(Long id) {} }
class JdbcTemplate {
<T> T queryForObject(String s, RowMapper<T> r, Object... a) { return null; }
interface RowMapper<T> { T mapRow(ResultSet rs, int n) throws SQLException; }
}
JdbcTemplate = 5주차 디자인 패턴의 집약인 이유는?
답:
1. 모든 결합:
좋은 라이브러리:
학습 정점:
이론↔실제:
6주차 — DB 접근의 진화 + 학습 도구
🧪 Part A — 학습 도구와 환경 (9 Unit) ✅
- Phase 1: JUnit (5)
- Phase 2: 웹 인프라 (4)
💾 Part B — DB 접근의 진화 (22 Unit)
- Phase 3: JDBC (3)
- Phase 4: Connection Pool (4)
- Phase 5: DataSource (4)
- Phase 6: 트랜잭션 ACID (6)
- Phase 7: JdbcTemplate (5)
총: 31 Unit ✅ (전체 완주!)
Phase 별 핵심:
Phase 1 (JUnit):
- 단위 테스트
- assertThat/매처
Phase 2 (웹 인프라):
- WAS, 서블릿/JSP
- SSR/CSR
Phase 3 (JDBC):
- 자바 DB 표준
- SQL 차이는 그대로
Phase 4 (Connection Pool):
- HikariCP, DB 세션
- DB Lock
Phase 5 (DataSource):
- 추상화 (5주차 정신)
- SOLID DIP
Phase 6 (ACID):
- Atomicity/Consistency/Isolation/Durability
- + 동시성 격리
Phase 7 (JdbcTemplate):
- 5주차 패턴의 집약
- 람다 결합
학습 흐름:
JDBC (3) — DB 접근 표준
↓
Connection Pool (4) — 성능 + 추상화 시작
↓
DataSource (5) — 5주차 정신 자바 표준
↓
ACID (6) — 트랜잭션 안전성
↓
JdbcTemplate (7) — 모든 학습의 결정체
→ 진화의 길
면접 핵심:
- 트랜잭션 ACID (가장 자주)
- 격리 수준 (Dirty/Non-repeatable/Phantom)
- Connection Pool (HikariCP)
- DataSource (DIP)
- JdbcTemplate (디자인 패턴)
- JPA 와 비교
→ 6주차 = 면접 보고
ILIC = 6주차 학습의 실제
ILIC 시스템:
- Spring Boot 3 + Vue 3
- 102 테이블
- 431 API
6주차 학습 활용:
- HikariCP (Connection Pool, Phase 4)
- DataSource (Phase 5)
- @Transactional (ACID, Phase 6)
- JdbcTemplate (Phase 7, 복잡 통계)
- JPA (Phase 3 후속, 주력)
- JUnit (Phase 1, 테스트)
→ ILIC = 6주차 학습의 살아있는 적용
6주차 전체 종합은?
답:
1. Part A:
Part B:
흐름:
결정체:
6주차 종합 졸업 시험:
25 문항, 분야별:
- Part A (테스트 + 웹 인프라): 9
- Phase 3 (JDBC): 4
- Phase 5 (DataSource): 3
- Phase 6 (트랜잭션 ACID): 5
- Phase 7 (JdbcTemplate): 4
→ 6주차 전체 점검
Q1 단위 테스트 가 통합 테스트 와 다른 점은?
단위 테스트는 하나의 단위 (메서드/클래스) 만 격리해서 검증한다. 통합 테스트는 여러 컴포넌트의 협력을 검증. 단위 테스트가 빠르고 디버깅 쉬움.
Q2 assertThat / 매처 사용의 장점은?
is,equalTo,hasSize,containsString등 자연어에 가까운 표현 가능. assertion 실패 시 메시지가 명확.
Q3 JUnit 이 매번 새 인스턴스 만드는 이유는?
테스트 메서드 간 상태 공유 방지 (격리). 한 테스트가 다른 테스트에 영향 주지 않게.
Q4 @BeforeEach 의 용도는?
매 테스트 메서드 전에 공통 픽스처 (fixture) 준비. DB 초기화, 객체 생성 등.
Q5 웹서버 vs WAS 의 차이?
웹서버 (Nginx/Apache): 정적 자원 처리. WAS (Tomcat): 동적 자원 (서블릿/JSP) 처리. 보통 웹서버가 앞단, WAS 가 뒤.
Q6 서블릿이란?
WAS 위에서 동작하는 자바 웹 컴포넌트. HTTP 요청 받아 응답 생성. Spring MVC 의 기반.
Q7 SSR vs CSR 차이?
SSR (서버 렌더링): 서버에서 HTML 완성, 전송. SEO 유리. CSR (클라이언트 렌더링): JS 가 브라우저에서 렌더. UX 부드러움.
Q8 JAR vs WAR 차이?
JAR: 자바 라이브러리/실행 파일. Spring Boot 는 내장 톰캣 + JAR. WAR: 외장 톰캣 등에 배포하는 웹 애플리케이션.
Q9 Spring Boot 가 JAR 를 선호하는 이유?
내장 톰캣 포함, 단일 파일 배포, 컨테이너 (Docker) 친화, 마이크로서비스 적합.
Q10 JDBC 등장 전의 고통은?
각 DB 마다 고유 API (Oracle/MySQL 별 다른 방식). DB 바꾸면 모든 코드 재작성. 심하면 바이너리 프로토콜을 소켓으로 직접 (지옥).
Q11 JDBC 가 통일한 3가지는?
(1) 연결 방식 (DriverManager.getConnection / Connection), (2) SQL 실행 (PreparedStatement.executeQuery/Update), (3) 결과 처리 (ResultSet).
Q12 JDBC 가 해결하지 않은 것은?
SQL 문법 차이 (LIMIT vs ROWNUM, AUTO_INCREMENT vs SEQUENCE 등). 페이징 / 자동 증가 방식 DB 마다 다름. 그래서 JPA/Hibernate (Dialect) 같은 상위 프레임워크 등장.
Q13 JDBC 와 5주차 디자인 패턴의 닮음은?
JDBC 의 Connection/Statement/ResultSet 은 인터페이스 (전략 패턴). DriverManager 가 URL 로 적절한 드라이버 선택. 5주차 ConnectionMaker 인터페이스 도입과 같은 정신.
Q14 DataSource 인터페이스의 핵심 메서드는?
Connection getConnection() throws SQLException단 하나. "커넥션 얻는 방법" 만 정의 (구현은 자유).
Q15 HikariCP → DBCP2 변경 시 애플리케이션 코드 변경은?
없음. 설정 (application.yml) 과 의존성 (build.gradle) 만 변경. 애플리케이션은
DataSource인터페이스에만 의존하므로 OCP 달성.
Q16 DataSource = SOLID DIP 의 구현체 인 이유?
고수준 (애플리케이션 ShipmentDao) 과 저수준 (HikariDataSource) 이 둘 다 DataSource (추상) 에 의존. 의존 방향 역전.
Q17 Atomicity 가 자바 Atomic 과 다른 점은?
자바 Atomic: 한 변수의 한 연산 (count++). DB Atomicity: 여러 SQL 묶음 (이체 = 출금 + 입금). 단위가 다름.
Q18 Consistency 가 보장하는 것은?
트랜잭션 후 DB 제약조건 (NOT NULL/UNIQUE/CHECK/FK) 항상 만족. 깨는 트랜잭션은 자동 rollback. + 비즈니스 규칙은 보통 애플리케이션이.
Q19 Dirty Read / Non-repeatable Read / Phantom Read 차이?
Dirty Read: 커밋 안 된 값 읽기. Non-repeatable Read: 같은 행 두 번 조회 시 값 다름. Phantom Read: 같은 범위 조회 시 새 행 등장. 격리 수준 RC/RR/SERIALIZABLE 가 단계별 차단.
Q20 Durability 가 ACID 중 가장 비싼 이유?
Commit 마다 fsync (디스크 강제 쓰기) 필요. 다른 성질 (A/C/I) 는 메모리 위주, Durability 만 디스크 I/O 강제.
Q21 세션1 미커밋 변경 + 세션2 조회 시 세션2 가 보는 것은?
변경 전 데이터 (격리). 세션1 의 변경은 자기 트랜잭션에서만 보임. 세션1 commit 후에야 세션2 도 새 값을 봄.
Q22 JdbcTemplate 이 숨기는 것은?
Connection 획득/반환, PreparedStatement 생성/해제, ResultSet 처리, SQLException → DataAccessException 변환, 자원 해제 순서. 개발자는 변하는 부분만.
Q23 queryForObject 결과 0건 / 2건 이상이면?
0건 → EmptyResultDataAccessException, 2건+ → IncorrectResultSizeDataAccessException. PK/UNIQUE 로 1건 보장된 쿼리에만 사용해야.
Q24 RowMapper 가 5주차 전략 패턴인 이유?
JdbcTemplate (변하지 않는 흐름, 컨텍스트) + RowMapper (변하는 매핑, 전략). 외부에서 람다로 주입 → 같은 SQL, 다른 매퍼 가능.
Q25 JdbcTemplate 이 5주차 디자인 패턴의 집약체인 이유?
(1) 관심사 분리 (인프라/비즈니스), (2) 템플릿 메소드 패턴 (이름 자체 "Template"), (3) 전략 패턴 (RowMapper 등), (4) OCP (새 쿼리 = 새 람다), (5) DI (DataSource 주입). + 3주차 람다 결합 → JDBC 직접 20+ 줄을 5-7 줄로.
1. JdbcTemplate = 디자인 패턴의 집약
2. 좋은 라이브러리 = 좋은 OOP
3. 6주차 학습의 정점
🛠️ Phase 7 — JdbcTemplate
✅ Unit 7.1 JDBC 만 쓸 때 반복 코드
✅ Unit 7.2 JdbcTemplate 등장 ★깊이
✅ Unit 7.3 update/queryForObject/query
✅ Unit 7.4 RowMapper
✅ Unit 7.5 JdbcTemplate 구조적 의미 ← 여기, Phase 7 완주!
🎉 F-LAB JAVA 6주차 — DB 접근의 진화 + 학습 도구 🎉
🧪 Part A — 학습 도구와 환경 ✅
✅ Phase 1: JUnit 테스트 (5 Unit)
✅ Phase 2: 웹 인프라 (4 Unit)
💾 Part B — DB 접근의 진화 ✅
✅ Phase 3: JDBC (3 Unit)
✅ Phase 4: Connection Pool (4 Unit) — Unit 4.2 ★깊이
✅ Phase 5: DataSource (4 Unit) — Unit 5.3 ★깊이
✅ Phase 6: 트랜잭션 ACID (6 Unit) — Unit 6.2~6.6 ★깊이 5개!
✅ Phase 7: JdbcTemplate (5 Unit) — Unit 7.2 ★깊이
총: 31 Unit / 31 Unit (100%!) ★ 깊이 Unit 8개 완주
→ 6주차의 정점 = 5주차 디자인 패턴 + 자바 표준 라이브러리 + DB 진화
→ ILIC 시스템의 실제 기반
→ 자바 백엔드 면접 보고
완료:
✅ 1주차 (자바 기본/OOP)
✅ 2주차 (메모리/JVM)
✅ 3주차 (제네릭/람다/스트림)
✅ 4주차 (멀티스레드/동시성)
✅ 5주차 (Spring IoC/DI/디자인 패턴)
✅ 6주차 (DB 접근의 진화) ← 방금 완주!
이후 (계획):
⏭ 7주차+ (예정)
ILIC 의 6주차 학습 활용:
- HikariCP (Connection Pool, Phase 4)
- JPA/Hibernate (Phase 3 후속, 주력)
- JdbcTemplate (Phase 7, 복잡 통계)
- @Transactional (Phase 6 ACID)
- DataSource 추상화 (Phase 5)
- JUnit 테스트 (Phase 1)
→ 모든 학습이 ILIC 에 직접
🏆🏆🏆 6주차 전체 완주 — DB 접근의 진화 + 학습 도구
31 Unit · 8 ★깊이 · 5주차 패턴의 결정체