[Day 27 | Spring] RowMapper와 BeanPropertyRowMapper

y♡ding·2024년 11월 19일

데브코스 TIL - Spring

목록 보기
18/46

RowMapper

BeanPropertyRowMapper

  • RowMapper는 스프링 JDBC에서 제공하는 인터페이스로, SQL 결과(ResultSet)를 Java 객체로 매핑하는 데 사용됩니다. 데이터베이스의 결과를 특정 자바 객체로 변환하기 위해 사용되며, SELECT 쿼리의 결과를 처리하는 데 주로 활용됩니다.

1. RowMapper의 역할

  • SQL 결과를 Java 객체로 변환:
    • 데이터베이스의 컬럼 이름과 자바 객체의 필드를 매핑하여 객체로 변환합니다.
  • 코드 재사용성 증가:
    • 객체 변환 로직을 분리하여 재사용 가능한 매핑 로직을 제공합니다.
  • 직접 매핑 구현 가능:
    • 단순 매핑은 BeanPropertyRowMapper를 활용하고, 복잡한 매핑은 RowMapper를 직접 구현합니다.

2. RowMapper 인터페이스 구조

메서드

RowMapper는 단일 메서드로 구성되어 있습니다.

public interface RowMapper<T> {
    T mapRow(ResultSet rs, int rowNum) throws SQLException;
}
  • mapRow(ResultSet rs, int rowNum):
    • ResultSet 객체의 현재 행을 읽고, 이를 변환하여 Java 객체를 반환합니다.
    • 매개변수:
      • rs: 쿼리 결과를 나타내는 ResultSet.
      • rowNum: 결과 집합 내에서 현재 행의 번호(0부터 시작).
    • 반환값:
      • 매핑된 객체(T).

3. 사용 예제

3.1 테이블과 매핑할 클래스 정의

데이터베이스의 users 테이블과 매핑할 클래스입니다.

@Getter
@Setter
public class User {
    private int id;
    private String name;
    private String email;

3.2 RowMapper 구현

User 객체로 결과를 매핑하기 위한 RowMapper를 직접 구현합니다.

import org.springframework.jdbc.core.RowMapper;

import java.sql.ResultSet;
import java.sql.SQLException;

public class UserRowMapper implements RowMapper<User> {

    @Override
    public User mapRow(ResultSet rs, int rowNum) throws SQLException {
        User user = new User();
        user.setId(rs.getInt("id"));
        user.setName(rs.getString("name"));
        user.setEmail(rs.getString("email"));
        return user;
    }
}
  • 매핑 로직:
    • ResultSet에서 데이터베이스 컬럼 값을 읽고, User 객체에 설정합니다.

3.3 JdbcTemplate과 함께 사용

JdbcTemplatequery 메서드에서 RowMapper를 사용하여 데이터를 객체로 변환합니다.

import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Repository;

import java.util.List;

@Repository
public class UserRepository {

    private final JdbcTemplate jdbcTemplate;

    public UserRepository(JdbcTemplate jdbcTemplate) {
        this.jdbcTemplate = jdbcTemplate;
    }

    public List<User> findAllUsers() {
        String sql = "SELECT id, name, email FROM users";
        return jdbcTemplate.query(sql, new UserRowMapper());
    }

    public User findUserById(int id) {
        String sql = "SELECT id, name, email FROM users WHERE id = ?";
        return jdbcTemplate.queryForObject(sql, new UserRowMapper(), id);
    }
}
  • query:
    • 여러 행의 결과를 처리하여 리스트로 반환.
  • queryForObject:
    • 단일 행의 결과를 처리하여 객체로 반환.

BeanPropertyRowMapper

  • BeanPropertyRowMapper는 스프링 JDBC에서 제공하는 RowMapper의 구현체로, SQL 결과(ResultSet)를 지정한 클래스의 객체로 자동 매핑해주는 유용한 도구입니다. 클래스의 속성 이름과 데이터베이스 컬럼 이름이 일치할 경우, 이를 자동으로 매핑하여 객체를 생성합니다.

1. 특징 및 사용 목적

  • 자동 매핑: SQL 쿼리의 결과(ResultSet)를 클래스의 필드 이름과 매칭하여 객체로 변환합니다.
  • Reflection 기반: Java Reflection을 사용하여 매핑 작업을 자동화합니다.
  • 단순화: 별도의 커스텀 매퍼 클래스를 작성하지 않아도 객체로 변환할 수 있습니다.

2. 사용 예제

2.1 예제 데이터베이스 테이블

다음과 같은 users 테이블을 가정합니다.

CREATE TABLE users (
    id INT AUTO_INCREMENT PRIMARY KEY,
    name VARCHAR(50),
    email VARCHAR(100)
);

2.2 매핑할 클래스

데이터베이스의 users 테이블과 매핑할 클래스는 다음과 같이 작성합니다.

@Getter
@Setter
public class User {
    private int id;
    private String name;
    private String email;
  • 클래스의 필드 이름이 데이터베이스 컬럼 이름과 일치해야 합니다. (컬럼 이름이 다를 경우 별도로 매핑 필요)

2.3 JdbcTemplate과 BeanPropertyRowMapper 사용

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

import java.util.List;

@Repository
public class UserRepository {

    private final JdbcTemplate jdbcTemplate;

    public UserRepository(JdbcTemplate jdbcTemplate) {
        this.jdbcTemplate = jdbcTemplate;
    }

    public List<User> findAllUsers() {
        String sql = "SELECT id, name, email FROM users";
        return jdbcTemplate.query(sql, new BeanPropertyRowMapper<>(User.class));
    }

    public User findUserById(int id) {
        String sql = "SELECT id, name, email FROM users WHERE id = ?";
        return jdbcTemplate.queryForObject(sql, new BeanPropertyRowMapper<>(User.class), id);
    }
}
  • new BeanPropertyRowMapper<>(User.class): SQL 결과를 User 객체로 자동 매핑합니다.
  • query: 여러 개의 결과를 리스트로 반환합니다.
  • queryForObject: 단일 결과를 객체로 반환합니다.

3. BeanPropertyRowMapper 작동 방식

  1. 클래스의 필드와 데이터베이스 컬럼 매칭
    • SQL 결과의 컬럼 이름과 클래스의 필드 이름을 대소문자를 구분하지 않고 매핑합니다.
    • 컬럼 이름이 snake_case일 경우, camelCase 필드로 자동 변환하여 매핑합니다.
    • 예: 데이터베이스 컬럼 user_email → 클래스 필드 userEmail.
  2. Setter 메서드 호출
    • Reflection을 통해 클래스의 Setter 메서드를 호출하여 값을 설정합니다.
    • 클래스에는 반드시 기본 생성자와 setter 메서드가 있어야 합니다.
  3. 예외 처리
    • 필드와 컬럼이 매칭되지 않으면 예외가 발생할 수 있습니다(DataAccessException).

4. 장점과 단점

장점

  1. 자동화: 데이터베이스의 결과를 간단히 객체로 변환할 수 있습니다.
  2. 간결성: RowMapper를 직접 구현할 필요가 없습니다.
  3. CamelCase 변환: 컬럼 이름이 snake_case 형식이어도 클래스 필드가 camelCase 형식이라면 자동으로 매핑됩니다.

단점

  1. 필드 이름 의존: 데이터베이스 컬럼 이름과 클래스 필드 이름이 반드시 일치해야 합니다.
  2. 퍼포먼스: Reflection을 사용하기 때문에 성능이 미세하게 저하될 수 있습니다.
  3. 커스텀 매핑 어려움: 복잡한 매핑 로직이 필요한 경우에는 적합하지 않습니다.

5. 컬럼 이름이 필드 이름과 다른 경우 처리 방법

5.1 SQL에서 별칭 사용

SQL 쿼리에서 컬럼 이름에 별칭을 지정하여 필드 이름과 일치시키는 방법입니다.

public User findUserById(int id) {
    String sql = "SELECT id AS id, name AS name, email AS email_address FROM users WHERE id = ?";
    return jdbcTemplate.queryForObject(sql, new BeanPropertyRowMapper<>(User.class), id);
}
  • SQL에서 email 컬럼 이름을 email_address로 변경하여 클래스 필드와 매칭합니다.

RowMapperBeanPropertyRowMapper 비교

특징RowMapperBeanPropertyRowMapper
매핑 방식개발자가 매핑 로직을 직접 작성Reflection을 통해 필드와 컬럼 이름 자동 매핑
유연성복잡한 매핑 로직에 적합단순 매핑 로직에 적합
컬럼-필드 이름 일치 여부불필요 (직접 매핑)컬럼 이름과 필드 이름이 일치해야 함
성능Reflection이 없으므로 더 빠름Reflection 사용으로 약간 느림
코드 간결성다소 코드가 길어질 수 있음코드가 더 간결

0개의 댓글