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이 존재하는데
각각 현재 행 데이터, 몇 번째 행인지를 나타낸다
'🍃 Spring' 카테고리의 다른 글
| 🌻ORM, MyBatis : SQL과 자바의 역할 분리 (0) | 2026.02.09 |
|---|---|
| @Transactional과 트랜잭션 정리 (0) | 2026.02.02 |
| AOP : @어노테이션으로 변경 (0) | 2026.01.27 |
| AOP 바인드 변수 완전정리 (0) | 2026.01.26 |
| 애스팩트 설정 : after / returning (0) | 2026.01.24 |