Java Category/Spring

[Spring DB] NamedParameterJdbcTemplate

ReBugs 2024. 3. 31.

NamedParameterJdbcTemplate은 Spring Framework의 JDBC 접근 방법 중 하나로, JdbcTemplate과 유사하게 작동하지만, SQL 파라미터를 이름으로 지정할 수 있다는 주요 차이점이 있다. 이는 코드의 가독성을 높이고, SQL 쿼리의 파라미터를 더 명확하게 만드는 데 도움을 준다.

CRUD

설정

NamedParameterJdbcTemplate 인스턴스를 생성해야 한다. 이는 보통 DataSource를 주입하여 생성된다.

@Autowired
private DataSource dataSource;

private NamedParameterJdbcTemplate jdbcTemplate;

@PostConstruct
public void postConstruct() {
    jdbcTemplate = new NamedParameterJdbcTemplate(dataSource);
}

 

 

Create

String insertSql = "INSERT INTO users (name, email) VALUES (:name, :email)";
MapSqlParameterSource parameters = new MapSqlParameterSource()
    .addValue("name", "John Doe")
    .addValue("email", "johndoe@example.com");

int rowsAffected = jdbcTemplate.update(insertSql, parameters);

 

 

Read

단일 객체 조회

String selectSql = "SELECT * FROM users WHERE id = :id";
SqlParameterSource namedParameters = new MapSqlParameterSource("id", 1);
User user = jdbcTemplate.queryForObject(selectSql, namedParameters, new BeanPropertyRowMapper<>(User.class));

 

리스트 조회

String selectAllSql = "SELECT * FROM users";
List<User> users = jdbcTemplate.query(selectAllSql, new MapSqlParameterSource(), new BeanPropertyRowMapper<>(User.class));

 

 

Update

String updateSql = "UPDATE users SET email = :email WHERE name = :name";
MapSqlParameterSource parameters = new MapSqlParameterSource()
    .addValue("email", "newemail@example.com")
    .addValue("name", "John Doe");

int rowsAffected = jdbcTemplate.update(updateSql, parameters);

 

 

Delete

String deleteSql = "DELETE FROM users WHERE id = :id";
SqlParameterSource namedParameters = new MapSqlParameterSource("id", 1);

int rowsAffected = jdbcTemplate.update(deleteSql, namedParameters);

 

 

SqlParameterSource

Spring의 JDBC 접근 방식에서 쿼리 파라미터를 정의할 때 사용되는 인터페이스로, 다양한 구현체를 통해 파라미터 값을 지정할 수 있다. 이 인터페이스를 사용하는 주된 목적은 SQL 쿼리 또는 업데이트 문에 동적으로 파라미터를 전달하는 것이다. 여기서는 SqlParameterSource의 두 가지 주요 구현체인 BeanPropertySqlParameterSource와 MapSqlParameterSource, 그리고 일반 Map을 사용한 방식에 대해 설명한다.

BeanPropertySqlParameterSource

BeanPropertySqlParameterSource는 객체의 속성을 SQL 파라미터로 사용하는 경우에 적합하다. 이 구현체는 객체의 getter 메소드를 통해 속성 값을 읽어, 파라미터의 이름과 값으로 매핑한다.

public class User {
    private String name;
    private String email;
    // getters and setters 생략
}

User user = new User();
user.setName("John Doe");
user.setEmail("johndoe@example.com");

SqlParameterSource namedParameters = new BeanPropertySqlParameterSource(user);

이 방식은 주로 객체의 필드를 데이터베이스의 컬럼과 매핑할 때 유용하며, 반복적인 코드 작성을 줄여준다.

MapSqlParameterSource

MapSqlParameterSource는 키-값 쌍을 이용하여 SQL 파라미터를 정의할 때 사용된다. MapSqlParameterSource는 SqlParameterSource 인터페이스의 구현체 중 하나로, 파라미터의 이름과 값을 맵핑하기 위해 내부적으로 Map을 사용한다.

SqlParameterSource namedParameters = new MapSqlParameterSource()
        .addValue("name", "John Doe")
        .addValue("email", "johndoe@example.com");

이 방식은 동적인 쿼리 생성 시나 특정 조건에 따라 다른 파라미터를 사용해야 할 때 매우 유용하다.

 

Map

일반 Map을 사용하여 파라미터를 정의하는 방법은 NamedParameterJdbcTemplate의 메소드에 파라미터로 Map<String, ?>을 직접 전달하는 것이다. 이 방법은 간단하고 직관적이지만, SqlParameterSource 구현체들이 제공하는 추가 기능은 없다.

Map<String, Object> parameters = new HashMap<>();
parameters.put("name", "John Doe");
parameters.put("email", "johndoe@example.com");

namedParameterJdbcTemplate.update("INSERT INTO users (name, email) VALUES (:name, :email)", parameters);

 

BeanPropertyRowMapper

BeanPropertyRowMapper는 JDBC 지원 부분에서 제공하는 유틸리티 클래스로, ResultSet의 행을 자바 객체로 매핑해주는 역할을 한다. 이 클래스를 사용하면, 데이터베이스 쿼리의 결과를 자바의 POJO(Plain Old Java Object)로 쉽게 변환할 수 있다.

POJO(Plain Old Java Objects)
"단순한 구식 자바 객체"를 의미한다.
이 용어는 특정 자바 모델이나 프레임워크, 규약에 종속되지 않는, 순수한 자바 객체를 지칭하기 위해 사용된다. POJO는 JavaBeans 규약을 따르기도 하지만, 필수는 아니다. 주로 데이터를 표현하는 데 사용되며, 로직을 담고 있는 비즈니스 객체로도 사용된다.

POJO의 주요 특징
-단순함: 복잡한 객체 모델이나 프레임워크에 의존하지 않는 가장 단순한 형태의 자바 객체이다.
-재사용성과 테스트 용이성: 특정 기술에 종속되지 않으므로, 다양한 환경에서 재사용하고 테스트하기가 쉽다.직렬화 가능: 객체의 상태를 저장하거나 네트워크를 통해 전송할 수 있다.
-캡슐화: 데이터와 데이터를 처리하는 로직을 하나의 단위로 묶어 관리한다.

BeanPropertyRowMapper는 RowMapper 인터페이스를 구현하고 있어, JdbcTemplate 또는 NamedParameterJdbcTemplate의 쿼리 메소드와 함께 사용될 수 있다.

관례 불일치

자바 객체는 카멜(camelCase) 표기법을 사용한다. itemName 처럼 중간에 낙타 봉이 올라와 있는 표기법이다. 반면에 관계형 데이터베이스에서는 주로 언더스코어를 사용하는 snake_case 표기법을 사용한다.

item_name 처럼 중간에 언더스코어를 사용하는 표기법이다. 이 부분을 관례로 많이 사용하다 보니 BeanPropertyRowMapper는 언더스코어 표기법을 카멜로 자동 변환해준다. 따라서 select item_name 으로 조회해도 setItemName() 에 문제 없이 값이 들어간다.

정리하면 snake_case는 자동으로 해결되니 그냥 두면 되고, 컬럼 이름과 객체 이름이 완전히 다른 경우에는 조회 SQL에서 별칭을 사용하면 된다.

 

사용 방법

BeanPropertyRowMapper의 인스턴스를 생성할 때는 매핑할 객체의 클래스 타입을 지정해야 한다. 이 클래스는 자바 빈 규약을 따르는 속성(즉, getter와 setter 메소드가 있는 속성)에 대해, 데이터베이스의 컬럼 이름과 같은 이름의 속성을 자동으로 매핑한다. 컬럼 이름과 속성 이름 사이에 대소문자 구분은 기본적으로 무시된다.

User 클래스

public class User {
    private Long id;
    private String name;
    private String email;
    // 게터와 세터 메소드 생략
}

 

BeanPropertyRowMapper 사용 예

import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.JdbcTemplate;

JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);
String sql = "SELECT id, name, email FROM users";

List<User> users = jdbcTemplate.query(sql, new BeanPropertyRowMapper<>(User.class));

 

 

KeyHolder

KeyHolder를 사용하는 과정은 자동 생성된 키, 특히 데이터베이스에서 새로운 레코드를 삽입한 후 생성된 기본 키(Primary Key) 값을 얻기 위해 사용된다. NamedParameterJdbcTemplate을 사용하는 경우, KeyHolder와 함께 작업을 실행하여 이러한 키 값을 추출할 수 있다. 주로 GeneratedKeyHolder 클래스의 인스턴스가 KeyHolder 인터페이스의 구현으로 사용된다.


KeyHolder 사용 예제

다음은 NamedParameterJdbcTemplate과 KeyHolder를 사용하여 데이터베이스에 레코드를 삽입하고, 자동 생성된 키를 추출하는 기본적인 과정을 보여주는 예제이다.

// NamedParameterJdbcTemplate 인스턴스 생성
NamedParameterJdbcTemplate namedParameterJdbcTemplate = new NamedParameterJdbcTemplate(dataSource);

// SQL 쿼리. :name과 :email은 파라미터 이름이다.
String sql = "INSERT INTO users(name, email) VALUES(:name, :email)";

// SqlParameterSource를 사용하여 SQL 파라미터 값을 설정한다.
SqlParameterSource parameters = new MapSqlParameterSource()
    .addValue("name", "홍길동")
    .addValue("email", "hong@example.com");

// GeneratedKeyHolder 인스턴스를 생성한다. 이 객체가 자동 생성된 키를 담게 된다.
KeyHolder keyHolder = new GeneratedKeyHolder();

// update 메소드를 실행하면서 SQL 실행, 파라미터, KeyHolder를 전달한다.
namedParameterJdbcTemplate.update(sql, parameters, keyHolder);

// KeyHolder를 통해 자동 생성된 키 값을 얻는다.
Number key = keyHolder.getKey();

이 예제에서는 NamedParameterJdbcTemplate의 update 메소드를 사용하여 데이터베이스에 새로운 레코드를 삽입한다. 삽입 시 사용되는 SQL 쿼리에는 이름과 이메일 주소를 나타내는 파라미터가 포함되어 있다. GeneratedKeyHolder 인스턴스는 이 쿼리가 실행된 후 생성된 키를 담게 된다. 작업이 성공적으로 완료된 후, KeyHolder의 getKey 메소드를 호출하여 자동 생성된 키 값을 얻을 수 있다.

KeyHolder의 사용은 자동 생성된 기본 키 정보가 필요할 때 매우 유용하며, 특히 새로 삽입된 레코드에 대한 후속 작업을 수행해야 할 경우에 필수적이다.

'Java Category > Spring' 카테고리의 다른 글

[Spring DB] 데이터 접근 계층 테스트  (0) 2024.04.02
[Spring DB] SimpleJdbcInsert  (0) 2024.04.01
[Spring DB] JDBC Template  (0) 2024.03.29
[Spring MVC] 파일 업로드  (0) 2024.03.25
[Spring MVC] 스프링 타입 컨버터  (1) 2024.03.24

댓글