◆ TURNING · DB

JDBC → MyBatis

Before / After 코드 비교

학습 목표

  • JDBC 의 반복 코드(boilerplate)를 직접 본다
  • MyBatis 가 그것을 어떻게 줄여주는지 안다
  • JDBC 30 줄 → MyBatis 1 줄의 변화를 라인별로 확인
  • 「왜 MyBatis 를 쓰는가?」를 한 문장으로 답할 수 있다

⚠️ JDBC 의 답답함

간단한 SELECT 한 번에 30 줄

JDBC 만으로 「회원 한 명 조회」를 짜보면 — 매 쿼리마다 같은 코드가 반복됩니다. 연결 만들기 → 쿼리 준비 → 파라미터 바인딩 → 실행 → 결과 가공 → 자원 정리. 한 곳이라도 빠뜨리면 메모리 누수나 SQL 오류.

BEFORE — 연결과 쿼리 준비


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();                      // ④ 실행
        // ... 다음 슬라이드: 결과 가공 + 자원 정리

BEFORE — 결과 매핑과 자원 정리


        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) {}
    }
}

BEFORE 의 7 가지 부담

단계코드위험
① 연결 만들기getConnection()매번 새 연결 → 느림
② 쿼리 준비prepareStatementSQL 문자열 직접 관리
③ 파라미터 바인딩setInt(1, id)인덱스(1) 기억 필요
④ 실행executeQuery
⑤ 결과 가공rs.getString(...)컬럼명 ↔ 필드 직접 매핑
⑥ 예외 처리try-catchSQLException 강제
⑦ 자원 정리finally close()한 곳 빠지면 메모리 누수

👉 회원 INSERT, UPDATE, 게시판 SELECT, ... 모든 쿼리에서 같은 7 단계 반복.

같은 일을 30 곳에서?

현실적인 게시판 프로젝트
  • 회원: insert, findByUserId, findById, updatePassword, ... 약 6 곳
  • 게시판: insert, findAll, findById, update, delete, count, paging, search, ... 약 10 곳
  • 댓글: insert, findByBoard, delete, ... 약 5 곳
  • 합계 — 같은 boilerplate 가 20+ 곳

한 곳에서 close() 한 줄 빠뜨리면 → 「Connection 풀 고갈」 → 시스템 다운. 숙련 개발자도 실수합니다.

🛠️ MyBatis 의 약속

「자바 ↔ SQL 통역사」

SQL 만 작성하세요. 연결 관리·파라미터·결과 매핑·자원 정리는 MyBatis 가 합니다.

JDBC 로 매번 직접 했던 7 단계 ↓ MyBatis 가 자동으로 처리 ↓ 개발자는 SQL 작성과 메서드 호출만

AFTER — Mapper 인터페이스와 XML

① 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>

AFTER — Service 에서 호출

③ Service 에서 사용


public Member find(String id) {
    return mapper.selectOne(id);   // ⭐ 한 줄!
}

인터페이스 메서드를 부르면 MyBatis 가 같은 id 의 SELECT 를 찾아 실행합니다. 연결·바인딩·매핑·정리는 모두 자동.

30 줄 — JDBC 의 분량

JDBC — 회원 한 명 조회

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()
}

1 줄 — MyBatis 의 분량

MyBatis — 같은 회원 조회

return mapper.selectOne(id);

+ XML 의 SELECT 한 줄

같은 결과 — 같은 SQL — 같은 회원. 단, 보일러플레이트 7 단계가 사라졌습니다.

MyBatis 가 자동으로 해주는 7 가지

단계JDBC 에서는MyBatis 에서는
연결 관리매번 직접자동 (커넥션 풀)
PreparedStatement 준비매번 직접자동
파라미터 바인딩인덱스로 직접#{id} 자동
실행직접자동
결과 → 객체 매핑setter 직접 호출resultType 자동
예외 처리SQLException 강제RuntimeException 변환
자원 정리finally close()자동

SQL 은 어디로 갔나?

JDBC 에서는 SQL 이 자바 코드 안에 문자열로 묻혀 있었습니다.

MyBatis 는 SQL 을 외부 XML 파일 로 분리합니다:

  • SQL 만 따로 모아 관리하기 쉬움
  • DB 관리자가 SQL 만 검토 가능
  • SQL 문법 하이라이팅 / 도구 지원
  • 긴 동적 SQL 도 깔끔하게

MyBatis vs JPA — 같은 자리, 다른 철학

항목MyBatisJPA (Hibernate)
SQL직접 작성자동 생성 (객체로)
학습 곡선낮음 — SQL 만 알면 됨높음 — JPA 개념 다수
SQL 제어완전제한적
복잡 쿼리편함QueryDSL 등 추가 필요
국내 비중높음 (SI·금융권)높음 (스타트업·신규)

👉 본 과정에서는 「선(先) MyBatis, 후(後) JPA」 — JPA 는 후속 과정.

왜 MyBatis 인가 — 한 문장

"SQL 을 직접 짜고 싶지만, 그 외의 boilerplate 는 다 자동화하고 싶다."

JDBC 는 너무 저수준 (boilerplate 가 많음). JPA 는 너무 추상화 (SQL 이 안 보임). MyBatis 는 그 가운데.

본 과정에서 다룰 MyBatis 기능

  • 기본 SELECT/INSERT/UPDATE/DELETE
  • #{} 파라미터 바인딩 (PreparedStatement 자동)
  • resultType — 결과 객체 매핑
  • useGeneratedKeys — INSERT 후 자동 증가 PK 받기
  • JOIN 결과 매핑
  • mapUnderscoreToCamelCase — 컬럼명 자동 변환

👉 동적 SQL (if·foreach), resultMap 등 고급은 후속 과정.

실험 — 직접 비교 체험

  1. 전 차시의 「DB 5 단계 지도」로 MyBatis 환경 구성
  2. 간단한 SELECT 메서드를 MyBatis 로 작성 (Mapper 인터페이스 + XML)
  3. 같은 SELECT 를 JDBC 로 작성 (참고용)
  4. 두 코드의 줄 수와 가독성을 직접 비교
  5. MyBatis 에서 close() 를 빠뜨릴 수 없다는 사실 확인 (작성할 자리가 없음)

🔄 Before / After

전 차시 끝

DB 와 MySQL 은 안다. 자바에서 어떻게 호출하는지는 막연.

이번 차시 끝

JDBC 의 7 단계 boilerplate 를 직접 봤다. MyBatis 가 그것을 자동화한다는 걸 라인별로 안다.

이번 차시의 데이터 흐름

Service
Mapper 인터페이스
Mapper XML SQL
DB
Mapper 두 박스가 흐름에 자리 잡음 — JDBC 의 boilerplate 를 대체

정리

오늘 들고 가는 것

  • JDBC 의 7 단계 boilerplate 를 직접 봤다
  • MyBatis = SQL 만 작성, 나머지는 자동
  • 30 줄 → 1 줄 + XML 한 줄로 줄어듦
  • SQL 직접 짜고 싶다」가 MyBatis 선택의 이유

다음: ◆ DB 5 단계 지도 — Spring 에 MyBatis 를 붙이는 5 곳.