◆ TURNING · DB

DB 붙이려면 어디를 손대나

5 단계 설정 변경 지도

학습 목표

  • Spring 에 DB 를 연결할 때 손대야 하는 5 곳을 외운다
  • 각 곳의 역할과 「빠뜨리면 어떤 오류」를 안다
  • 「DB 안 됨」 오류를 만나면 5 곳을 차례로 점검한다

⚠️ 진짜로 자주 마주치는 답답함

학생들이 가장 많이 외치는 말

"분명 코드대로 했는데 DB 가 안 돼요..."

Spring 에서 DB 연결은 한 곳만 손대서 되는 일이 아닙니다. 여러 파일이 동시에 협업해야 합니다. 어디 하나가 빠지면 전체가 동작 안 합니다.

왜 이렇게 복잡한가

Spring Legacy 의 자동 설정은 거의 없습니다. 모든 부품을 우리가 직접 등록해줘야 합니다:

  • JDBC 드라이버 (Maven)
  • 커넥션 풀 (HikariCP)
  • SqlSessionFactory (MyBatis 의 핵심)
  • Mapper 자동 스캔
  • 각 Mapper 인터페이스 + XML
  • Service 에서 Mapper 주입

이걸 5 단계로 정리해 두면 매번 막막함이 줄어듭니다.

🛠️ 5 단계 지도

┌──────────────────────────────────────────────┐ │ ① pom.xml — 라이브러리 5 개 │ │ ② root-context.xml — 3 개 Bean 등록 │ │ ③ mybatis-config — 카멜/스네이크 옵션 │ │ ④ Mapper 인터페이스 + XML │ │ ⑤ Service 에서 @Autowired │ └──────────────────────────────────────────────┘

👉 이 5 곳 중 한 곳이라도 빠지면 전체가 동작 안 함.

① pom.xml — DB 드라이버와 풀


<!-- MySQL 드라이버 -->
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-j</artifactId>
    <version>8.0.33</version>
</dependency>

<!-- HikariCP 커넥션 풀 -->
<dependency>
    <groupId>com.zaxxer</groupId>
    <artifactId>HikariCP</artifactId>
    <version>5.0.1</version>
</dependency>

① pom.xml — MyBatis 와 Spring JDBC


<!-- MyBatis + Spring 통합 -->
<dependency>
    <groupId>org.mybatis</groupId>
    <artifactId>mybatis</artifactId>
    <version>3.5.13</version>
</dependency>
<dependency>
    <groupId>org.mybatis</groupId>
    <artifactId>mybatis-spring</artifactId>
    <version>3.0.2</version>
</dependency>

<!-- Spring 의 JDBC 추상화 -->
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-jdbc</artifactId>
    <version>5.3.30</version>
</dependency>

① pom.xml 빠뜨리면

증상
  • "Cannot find class: com.mysql.cj.jdbc.Driver"
  • "BeanCreationException: ... HikariConfig"
  • "NoClassDefFoundError"
⚠️ Maven Update 잊지 말기

pom.xml 수정 후 반드시 프로젝트 우클릭 → Maven → Update Project. 안 하면 빨간 줄이 안 사라짐.

② root-context.xml — DataSource


<!-- (1) HikariCP 설정 객체 -->
<bean id="hikariConfig" class="com.zaxxer.hikari.HikariConfig">
    <property name="driverClassName" value="com.mysql.cj.jdbc.Driver" />
    <property name="jdbcUrl"
        value="jdbc:mysql://localhost:3306/spring_db?serverTimezone=UTC" />
    <property name="username" value="root" />
    <property name="password" value="1234" />
</bean>

<!-- (2) DataSource (실제 DB 연결의 진입점) -->
<bean id="dataSource" class="com.zaxxer.hikari.HikariDataSource"
      destroy-method="close">
    <constructor-arg ref="hikariConfig" />
</bean>

② root-context.xml — MyBatis 연결


<!-- (3) MyBatis SqlSessionFactory -->
<bean id="sqlSessionFactory"
      class="org.mybatis.spring.SqlSessionFactoryBean">
    <property name="dataSource" ref="dataSource" />
    <property name="configLocation"
        value="classpath:mybatis-config.xml" />
    <property name="mapperLocations"
        value="classpath:com/smhrd/mapper/*Mapper.xml" />
</bean>

<!-- (4) Mapper 자동 스캔 -->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
    <property name="basePackage" value="com.smhrd.mapper" />
</bean>

② 각 Bean 의 역할

Bean역할
hikariConfigDB 연결 정보(URL, 계정 등)
dataSource실제 연결을 만들고 풀로 관리
sqlSessionFactoryMyBatis 의 핵심. SQL 실행을 책임
MapperScannerConfigurer지정 패키지의 Mapper 인터페이스를 자동 스캔하고 Bean 으로 등록

👉 MapperScannerConfigurer 덕분에 우리가 매 Mapper 를 일일이 등록 안 해도 됨.

② 빠뜨리면

증상
  • "BeanCreationException: dataSource"
  • "No qualifying bean of type 'SqlSessionFactory'"
  • "Mapper 인터페이스가 자동 주입 안 됨"

DB 연결 정보 자체가 틀린 건지(URL/계정), Bean 등록이 빠진 건지를 가려야 합니다.

③ mybatis-config.xml


<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
    "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>

    <settings>
        <!-- ⭐ 카멜 ↔ 스네이크 자동 변환 -->
        <setting name="mapUnderscoreToCamelCase" value="true" />

        <!-- SQL 로그 출력 (개발 시) -->
        <setting name="logImpl" value="STDOUT_LOGGING" />
    </settings>

</configuration>

👉 mapUnderscoreToCamelCase=true 가 핵심.

③ 빠뜨리면 가장 흔한 함정

증상 — "데이터가 모두 null 이에요"

DB:    created_at = '...'  (스네이크)
VO:    LocalDateTime createdAt   (카멜)
결과:  b.getCreatedAt() == null!

SELECT 는 성공하는데 객체 필드가 null 이면 → 이름 매핑 실패.

mapUnderscoreToCamelCase=true 로 해결. 상세는 다음 차시(◆ 카멜·스네이크 함정).

④ Mapper 인터페이스 (자바)


// src/main/java/com/smhrd/mapper/MemberMapper.java
package com.smhrd.mapper;

import com.smhrd.domain.Member;
import org.apache.ibatis.annotations.Mapper;

@Mapper
public interface MemberMapper {
    Member selectOne(String id);
    void   insert(Member m);
}

④ Mapper XML (SQL)


<!-- src/main/resources/com/smhrd/mapper/MemberMapper.xml -->
<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>

    <insert id="insert" parameterType="com.smhrd.domain.Member">
        INSERT INTO mymember(id, pwd)
        VALUES(#{id}, #{pwd})
    </insert>

</mapper>

④ 매칭 규칙 4 가지

  • 패키지·풀클래스명: 인터페이스의 풀 클래스명 = XML 의 namespace
  • 메서드명: 인터페이스 메서드명 = XML 의 id
  • 파일 위치: XML 은 root-context.xmlmapperLocations 가 가리키는 경로
  • 패키지 스캔: 인터페이스는 MapperScannerConfigurerbasePackage 안에
한 글자라도 어긋나면

"Invalid bound statement" 또는 "Method not found" 오류. 가장 빈번한 함정.

④ 빠뜨리면

증상별 의심할 곳
증상의심
No qualifying bean of type 'XxxMapper'인터페이스가 스캔 패키지 밖에 있음
Invalid bound statement (not found)namespace 또는 id 오타
XML 자체를 못 찾음mapperLocations 경로 틀림

⑤ Service 에서 @Autowired


@Service
public class MemberService {

    @Autowired
    private MemberMapper mapper;     // ← 이 한 줄

    public Member find(String id) {
        return mapper.selectOne(id);
    }
}

👉 MapperScannerConfigurer 가 자동 등록한 Mapper Bean 을 받음.

⑤ 빠뜨리면

증상

NullPointerException — mapper 변수가 null 인 채로 메서드 호출됨.

@Autowired 가 빠지면 그 자리는 그냥 null. 그래도 컴파일은 되니 실행해야 알 수 있음.

5 단계 한눈에 다시

┌─────────────────────────────────────────────────────┐ │ ① pom.xml │ │ ├─ mysql-connector-j │ │ ├─ HikariCP │ │ ├─ mybatis + mybatis-spring │ │ └─ spring-jdbc │ │ │ │ ② root-context.xml │ │ ├─ hikariConfig (DB 정보) │ │ ├─ dataSource │ │ ├─ sqlSessionFactory │ │ └─ MapperScannerConfigurer │ │ │ │ ③ mybatis-config.xml │ │ └─ mapUnderscoreToCamelCase = true │ │ │ │ ④ Mapper 인터페이스 + XML (namespace/id 매칭) │ │ │ │ ⑤ Service @Autowired Mapper │ └─────────────────────────────────────────────────────┘

「DB 안 됨」 오류 시 점검 흐름

증상1순위 의심점검 단계
Cannot create connectionDB URL/계정/MySQL 가동
No class found의존성 누락
No qualifying beanBean 등록 누락② or ④
Invalid bound statementnamespace·id 오타
필드값 모두 null매핑 옵션
NullPointerException at mapper@Autowired 누락

실전 디버깅 팁

  • Tomcat 시작 로그를 끝까지 보기 — Bean 생성 실패는 시작 시 발생
  • SQL 로그 켜기 — 실제 SQL 이 실행됐는지 즉시 확인
  • DB 도구로 SQL 직접 실행 — Mapper 의 SQL 이 진짜 동작하는지 분리해서 확인
  • 한 단계씩 좁혀가기 — 5 단계를 머리부터 차례로

🔄 Before / After

전 차시

DB 가 안 되면 어디부터 봐야 할지 막막했다. 한 곳 고치면 다른 곳이 또 깨졌다.

이번 차시 끝

5 단계 지도를 외운다. DB 안 됨 오류를 만나면 5 곳을 차례로 점검한다.

이번 차시의 데이터 흐름

5 단계 설정
Spring 컨테이너
Mapper 자동 등록
Service 주입
「설정 지도」가 흐름 시작점에 자리잡음 — 모든 DB 연동의 토대

정리

오늘 들고 가는 것

  • DB 연결의 5 단계: pom.xml → root-context.xml → mybatis-config.xml → Mapper(I/F+XML) → Service @Autowired
  • 각 단계별 빠뜨리면 어떤 오류가 나는지 외운다
  • 오류 메시지로 어느 단계인지 역추적할 수 있다
  • 「DB 안 됨」 오류 디버깅 1순위 점검표

다음: HikariCP 커넥션 풀 — 풀이 왜 필요한가.