🍃 Spring

스프링에서의 JDBC : JdbcTemplate 클래스를 사용하는 스프링

보배 진 2026. 1. 28. 09:58

 

1. DAO에서 매번 connect/disconnect를 수행

DAO에서 매번 

1. 드라이버 로드

2. DB 연결

3. SQL문 수행

4. DB 연결 해제

이 과정을 매번 수행했는데

👉 1, 2, 4번이 매번 반복되는 걸 볼 수 있다

 

 

이 반복되는 것의 정체

횡단관심사, 어드바이스

▪ 비즈니스 로직과 직접 상관은 없지만

▪ 모든 곳에 공통적으로 등장

ex) DB연결/해제, 트랜잭션, 로깅, 보안

 

 

2. 반복되는 로직(1, 2, 4)들을 '모듈화'

public boolean insertBoard(BoardDTO dto) {
    Connection conn = JDBCUtil.connect();
    PreparedStatement pstmt = null;

    try {
        pstmt = conn.prepareStatement(INSERT);
        pstmt.setString(1, dto.getTitle());
        pstmt.setString(2, dto.getWriter());
        pstmt.setString(3, dto.getContent());
        int rs = pstmt.executeUpdate();
        if(rs <= 0) {
            return false;
        }
    } catch (SQLException e) {
        e.printStackTrace();
    }

    JDBCUtil.disconnect(conn, pstmt);

    return true;
}

 

connect() / disconnect() 👉 공통 로직

SQL 수행 부분 👉 변하는 로직

 

JDBCUtil로 반복되는 로직

JDBCUtil .connect() : 이런식으로 언급하여 사용을 하기 시작했다

➡ 템플릿 패턴 코드의 시초

 

 

그래서 지금 본 1), 2)번 모두 자바에서의 템플릿이었다

 

3) JdbcTemplate 클래스를 사용하는 스프링

개발자가 하던 것 JdbcTemplate이 대신
드라이버 로드 O
커넥션 생성/해제 O
예외 처리 O
자원 반납 O

 

개발자는 이제 SQL + 파라미터만 작성하면 된다

 

<!-- jstl -->
<dependency>
    <groupId>jakarta.servlet.jsp.jstl</groupId>
    <artifactId>jakarta.servlet.jsp.jstl-api</artifactId>
    <version>3.0.0</version>
</dependency>

.jar ▶ pom.xml에 DI

 

 

insertBoard의 핵심의 위의 코드와 같다

 

 

 

JdbcTemplate의 진짜 역할

public boolean insertBoard(BoardDTO dto) {
    if(jdbcTemplate.update(INSERT) <= 0) {
        return false;
    }
    return true;
}

insertBoard의 기본구조 : 결과가 잘 됐으면 true, 아니면 false
“이제 결과를 누구를 통해 받을 거면 애플워치” 
나에게 있어서 애플워치는 jdbcTemplate이다

 

 

 

public class PlusBoardDAO {
@Autowired // 의존주입
private JdbcTemplate jdbcTemplate;

private static final String INSERT = "INSERT INTO BOARD(TITLE,WRITER,CONTENT) VALUES(?,?,?)";
public boolean insertBoard(BoardDTO dto) {
    if(jdbcTemplate.update(INSERT) <= 0) {
        return false;
    }
    return true;
}

jdbcTemplate을 사용하려면 멤버 변수가 있어야 함
멤버 변수를 사용하려면 의존주입을 해야함

의존 주입을 하려면 객체 생성을 해야 함

 

 

객체 생성

<bean class="org.apache.commons.dbcp.BasicDataSource" id="dataSource">
     <property name="driverClassName" value="com.mysql.cj.jdbc.Driver" />
     <property name="url" value="jdbc:mysql://localhost:3306/teemo" />
     <property name="username" value="root" />
     <property name="password" value="1234" />
</bean>
<bean class="org.springframework.jdbc.core.JdbcTemplate" id="jdbcTemplate">
     <property name="dataSource" ref="dataSource" />
</bean>

객체 생성 ==  new, <bean>, @Component

 

 

스프링에서 주는 프레임워크는 대부분 어노테이션 적용이 안된다

때문에 pom.xml에서 설정을 해주어야 한다

다시 정리하면, 스프링이 제공하는 기반 객체(JdbcTemplate, DataSource 등)
개발자가 직접 @Component 붙이는 대상이 아니기 때문에
설정(pom.xml + bean 등록) 이 필요하다

 

객체 생성하려고 보니까 데이터 소스가 필요하기 때문에 데이터 소스도 준다

dataSource : id와 ref에는 객체명이 들어가야 하므로 동일한 이름이 들어가야 한다

 

 


 

PlusBoardDAO.java 전체코드

package com.example.biz.board.impl;

import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.stereotype.Repository;

import com.example.biz.board.BoardDTO;

@Repository
public class PlusBoardDAO {
	@Autowired // 의존주입
	private JdbcTemplate jdbcTemplate;
		
	private static final String SELECT_ALL = "SELECT * FROM BOARD ORDER BY BID DESC";
	private static final String SELECT_ONE = "SELECT * FROM BOARD WHERE BID=?";
	
	private static final String INSERT = "INSERT INTO BOARD(TITLE,WRITER,CONTENT) VALUES(?,?,?)";
	private static final String UPDATE = "UPDATE BOARD SET CNT=CNT+1 WHERE BID=?";
	private static final String DELETE = "DELETE FROM BOARD WHERE BID=?";
	
	public boolean insertBoard(BoardDTO dto) {
		System.out.println("[로그] inserBoard 시작");
		if(jdbcTemplate.update(INSERT, dto.getTitle(), dto.getWriter(), dto.getContent()) <= 0) {
			return false;
		}
		return true;
	}
	// jdbcTemplate을 사용하려면 멤버 변수가 있어야 함
	// 멤버 변수를 사용하려면 의존주입을 해야함
	// 의존 주입을 하려면 객체 생성을 해야 함
	
	public boolean updateBoard(BoardDTO dto) {
		System.out.println("[로그] updateBoard 시작");
		if(jdbcTemplate.update(UPDATE, dto.getBid()) <= 0) {
			return false;
		}
		return true;
	}
	
	public boolean deleteBoard(BoardDTO dto) {
		System.out.println("[로그] deleteBoard 시작");
		if(jdbcTemplate.update(DELETE, dto.getBid()) <= 0) {
			return false;
		}
		return true;
	}
	
	public BoardDTO getBoard(BoardDTO dto) {
		// return jdbcTemplate.queryForObject(SELECT_ONE, 어떻게 반환할지, 파라미터 정보);
		// select 류는 반환하는 값이 있기 떄문에 어떻게 반환할지 알려줘야 한다
		return jdbcTemplate.queryForObject(SELECT_ONE, new BoardRowMapper(), dto.getBid());
	}
	
	public List<BoardDTO> getBoardList(BoardDTO dto){
		return jdbcTemplate.query(SELECT_ALL, new BoardRowMapper());
	}
}

// jdbcTemplate이 사용할 수 있도록 만들어야 한다
class BoardRowMapper implements RowMapper<BoardDTO> {
	
	@Override
	public BoardDTO mapRow(ResultSet rs, int rowNum) throws SQLException{
		BoardDTO data = new BoardDTO();
		data.setBid(rs.getInt("BID"));
		data.setTitle(rs.getString("TITLE"));
		data.setWriter(rs.getString("WRITER"));
		data.setContent(rs.getString("CONTENT"));
		data.setRegdate(rs.getDate("REGDATE"));
		data.setCnt(rs.getInt("CNT"));
		return data;
	}
}

 

 

 

BoardRowMapper 분석 

class BoardRowMapper implements RowMapper<BoardDTO> {
	
	@Override
	public BoardDTO mapRow(ResultSet rs, int rowNum) throws SQLException{
		BoardDTO data = new BoardDTO();
		data.setBid(rs.getInt("BID"));
		data.setTitle(rs.getString("TITLE"));
		data.setWriter(rs.getString("WRITER"));
		data.setContent(rs.getString("CONTENT"));
		data.setRegdate(rs.getDate("REGDATE"));
		data.setCnt(rs.getInt("CNT"));
		return data;
	}
}

이름이 똑같더라도 어떤 컬럼이 어떤 멤버 변수인지 알려줘야 한다

 jdbcTemplate이 사용할 수 있도록 만들어야 한다 그래서 implements를 해준다

 

ResultSet을 DTO로 변환하는 역할을 해준다

mapRow()를 보면 ResultSet rs와 int rowNum이 존재하는데

각각 현재 행 데이터, 몇 번째 행인지를 나타낸다