Before / After 코드 비교
JDBC 만으로 「회원 한 명 조회」를 짜보면 — 매 쿼리마다 같은 코드가 반복됩니다. 연결 만들기 → 쿼리 준비 → 파라미터 바인딩 → 실행 → 결과 가공 → 자원 정리. 한 곳이라도 빠뜨리면 메모리 누수나 SQL 오류.
public Member selectOne(String id) {
Connection conn = null;
PreparedStatement ps = null;
ResultSet rs = null;
try {
conn = dataSource.getConnection(); // ① 연결
String sql = "SELECT id, pwd FROM mymember WHERE id = ?";
ps = conn.prepareStatement(sql); // ② 쿼리 준비
ps.setString(1, id); // ③ 파라미터
rs = ps.executeQuery(); // ④ 실행
// ... 다음 슬라이드: 결과 가공 + 자원 정리
if (rs.next()) { // ⑤ 결과 가공
Member m = new Member();
m.setId(rs.getString("id"));
m.setPwd(rs.getString("pwd"));
return m;
}
return null;
} catch (SQLException e) {
throw new RuntimeException(e); // ⑥ 예외
} finally { // ⑦ 자원 정리
try { if (rs != null) rs.close(); } catch (Exception ignored) {}
try { if (ps != null) ps.close(); } catch (Exception ignored) {}
try { if (conn != null) conn.close(); } catch (Exception ignored) {}
}
}
| 단계 | 코드 | 위험 |
|---|---|---|
| ① 연결 만들기 | getConnection() | 매번 새 연결 → 느림 |
| ② 쿼리 준비 | prepareStatement | SQL 문자열 직접 관리 |
| ③ 파라미터 바인딩 | setInt(1, id) | 인덱스(1) 기억 필요 |
| ④ 실행 | executeQuery | — |
| ⑤ 결과 가공 | rs.getString(...) | 컬럼명 ↔ 필드 직접 매핑 |
| ⑥ 예외 처리 | try-catch | SQLException 강제 |
| ⑦ 자원 정리 | finally close() | 한 곳 빠지면 메모리 누수 |
👉 회원 INSERT, UPDATE, 게시판 SELECT, ... 모든 쿼리에서 같은 7 단계 반복.
한 곳에서 close() 한 줄 빠뜨리면 → 「Connection 풀 고갈」 → 시스템 다운. 숙련 개발자도 실수합니다.
SQL 만 작성하세요. 연결 관리·파라미터·결과 매핑·자원 정리는 MyBatis 가 합니다.
① Mapper 인터페이스 (자바)
package com.smhrd.mapper;
@Mapper
public interface MemberMapper {
Member selectOne(String id);
}
② Mapper XML (SQL)
<mapper namespace="com.smhrd.mapper.MemberMapper">
<select id="selectOne"
parameterType="string"
resultType="com.smhrd.domain.Member">
SELECT id, pwd FROM mymember WHERE id = #{id}
</select>
</mapper>
③ Service 에서 사용
public Member find(String id) {
return mapper.selectOne(id); // ⭐ 한 줄!
}
인터페이스 메서드를 부르면 MyBatis 가 같은 id 의 SELECT 를 찾아 실행합니다. 연결·바인딩·매핑·정리는 모두 자동.
Connection conn = null;
PreparedStatement ps = null;
ResultSet rs = null;
try {
conn = ds.getConnection();
ps = conn.prepareStatement(
"SELECT id, pwd FROM mymember WHERE id = ?");
ps.setString(1, id);
rs = ps.executeQuery();
if (rs.next()) {
Member m = new Member();
m.setId(rs.getString("id"));
m.setPwd(rs.getString("pwd"));
return m;
}
return null;
} catch (SQLException e) {
throw new RuntimeException(e);
} finally {
// rs / ps / conn 각각 close()
}
return mapper.selectOne(id);
+ XML 의 SELECT 한 줄
같은 결과 — 같은 SQL — 같은 회원. 단, 보일러플레이트 7 단계가 사라졌습니다.
| 단계 | JDBC 에서는 | MyBatis 에서는 |
|---|---|---|
| 연결 관리 | 매번 직접 | 자동 (커넥션 풀) |
| PreparedStatement 준비 | 매번 직접 | 자동 |
| 파라미터 바인딩 | 인덱스로 직접 | #{id} 자동 |
| 실행 | 직접 | 자동 |
| 결과 → 객체 매핑 | setter 직접 호출 | resultType 자동 |
| 예외 처리 | SQLException 강제 | RuntimeException 변환 |
| 자원 정리 | finally close() | 자동 |
JDBC 에서는 SQL 이 자바 코드 안에 문자열로 묻혀 있었습니다.
MyBatis 는 SQL 을 외부 XML 파일 로 분리합니다:
| 항목 | MyBatis | JPA (Hibernate) |
|---|---|---|
| SQL | 직접 작성 | 자동 생성 (객체로) |
| 학습 곡선 | 낮음 — SQL 만 알면 됨 | 높음 — JPA 개념 다수 |
| SQL 제어 | 완전 | 제한적 |
| 복잡 쿼리 | 편함 | QueryDSL 등 추가 필요 |
| 국내 비중 | 높음 (SI·금융권) | 높음 (스타트업·신규) |
👉 본 과정에서는 「선(先) MyBatis, 후(後) JPA」 — JPA 는 후속 과정.
"SQL 을 직접 짜고 싶지만, 그 외의 boilerplate 는 다 자동화하고 싶다."
JDBC 는 너무 저수준 (boilerplate 가 많음). JPA 는 너무 추상화 (SQL 이 안 보임). MyBatis 는 그 가운데.
👉 동적 SQL (if·foreach), resultMap 등 고급은 후속 과정.
DB 와 MySQL 은 안다. 자바에서 어떻게 호출하는지는 막연.
JDBC 의 7 단계 boilerplate 를 직접 봤다. MyBatis 가 그것을 자동화한다는 걸 라인별로 안다.
다음: ◆ DB 5 단계 지도 — Spring 에 MyBatis 를 붙이는 5 곳.