728x90

들어가며,

 

JdbcTemplate은 스프링 프레임워크에서 제공하는 JDBC의 간소화된 버전으로, 템플릿 콜백 패턴을 사용하여 반복적인 JDBC 코드를 더 간편하게 작성할 수 있도록 도와줍니다.

JdbcTemplate이 제공하는 메서드들은 내부적으로 Connection, Statement, ResultSet 등의 자원을 생성하고 관리하여, 이러한 자원을 직접 다룰 필요가 없습니다.

 

템플릿 콜백 패턴?

템플릿 콜백 패턴은 클래스의 메서드가 호출되면서 특정 동작을 수행하는 디자인 패턴입니다.

JDBC Template에서는 JdbcTemplate 클래스를 사용하며, 이 패턴은 주로 execute() 메서드와 함께 사용됩니다.

 

Row Mapper를 콜백 인터페이스로 사용해, DB에서 조회한 결과를 객체에 매핑하는 역할을 합니다.

 

import org.springframework.jdbc.core.RowMapper;
import java.sql.ResultSet;
import java.sql.SQLException;

public class EmployeeRowMapper implements RowMapper<Employee> {

    @Override
    public Employee mapRow(ResultSet resultSet, int rowNum) throws SQLException {
        Employee employee = new Employee();
        employee.setId(resultSet.getLong("id"));
        employee.setName(resultSet.getString("name"));
        employee.setSalary(resultSet.getDouble("salary"));
        // 필요한 다른 속성들 설정
        return employee;
    }
}

 

기존의 JDBC에서 ResultSet을 사용해 처리하던 부분을 Row Mapper를 통해 해결한다.
// 반복문을 통해 ResultSet 결과 처리
while (resultSet.next()) {
    // 결과 처리
    String columnValue = resultSet.getString("column_name");
    // 추가로 처리할 작업 수행
}

// rowMapper를 이용해 구현
while(resultSet 이 끝날 때까지) {
rowMapper(rs, rowNum)
}

 

Statement는 어떻게 대신 처리해주나?

update(): INSERT, UPDATE, DELETE 등의 쿼리를 실행할 때 사용됩니다. 내부적으로 Statement 관리를 처리합니다.

String sql = "update item set item_name=?, price=?, quantity=? where id=?";
template.update(sql,
    itemName,
    price,
    quantity,
    itemId);

 

추가로 batchUpdate()메서드를 이용하면 여러 개의 SQL 문을 일괄로 처리할 수 있습니다.

update 메서드를 이용해서 파라미터를 바인딩하여 SQL문을 처리할 수 있습니다.
그러나, 이렇게 순서대로 바인딩 하는 경우, 순서의 변경으로 인해 데이터 장애가 발생할 위험이 있습니다.

NamedParameterJdbcTemplate

이름을 지정해서 바인딩하여 위와 같은 문제를 해결할 수 있습니다.

@Slf4j
@Repository
public class JdbcTemplateItemRepositoryV2 implements ItemRepository {
    
    private final NamedParameterJdbcTemplate template;
    
    public JdbcTemplateItemRepositoryV2(DataSource dataSource) {
    	this.template = new NamedParameterJdbcTemplate(dataSource);
    }
    
    @Override
    public Item save(Item item) {
        String sql = "insert into item (item_name, price, quantity) values (:itemName, :price, :quantity)";
        SqlParameterSource param = new BeanPropertySqlParameterSource(item);
        KeyHolder keyHolder = new GeneratedKeyHolder();
        template.update(sql, param, keyHolder);
        
        Long key = keyHolder.getKey().longValue();
        item.setId(key);
        return item;
    }

 

이름 지정 파라미터를 사용하는 방식에서는 Map과 같이 Key, Value 데이터 구조로 전달해야 합니다.

자주 사용하는 종류는 아래와 같습니다.
Map
SqlParameterSource
 - MapSqlParameterSource
 - BeanPropertySqlParameterSource

 

Map은 단순히 Map<String, Object>를 Map.of("id", id)로 받아 param 으로 사용합니다.

MapSqlParameterSource는 .addValue를 통해 부분적으로 조정이 가능하다. Update()메서드와 같은 경우에 사용이 가능합니다.

대부분의 경우는 BeanPropertySqlParameterSource를 사용합니다.

이는 데이터 값을 자동으로 생성해주기 때문에 

 

SimpleJdbcInsert

private final SimpleJdbcInsert jdbcInsert;
public JdbcTemplateItemRepositoryV3(DataSource dataSource) {
    this.template = new NamedParameterJdbcTemplate(dataSource);
    this.jdbcInsert = new SimpleJdbcInsert(dataSource)
    .withTableName("item")
    .usingGeneratedKeyColumns("id");
public Item save(Item item) {
    SqlParameterSource param = new BeanPropertySqlParameterSource(item);
    Number key = jdbcInsert.executeAndReturnKey(param);
    item.setId(key.longValue());
    return item;
}

 

jdbcInsert.excuteAndReturnKey(param)을 사용해 Insert SQL을 실행할 수 있습니다.

 

 

+ Recent posts