본문 바로가기
우아한테크코스 4기/레벨2

[Spring] NamedParameterJdbcTemplate 사용하기

by 나는후니 2022. 4. 21.

NamedParameterJdbcTemplate

Spring에서는 데이터에 접근하는 기능으로 JdbcTemplate을 구현한 다양한 구현체를 갖고 있습니다.

이번 포스팅에서는 JdbcTemplate 를 구현한 구현체인 NamedParameterJdbcTemplate 를 사용할 때 얻을 수 있는 편리함에 대해 글을 작성해보고자 합니다.

 

NamedParameterJdbcTemplate 는 Jdbc를 사용할 때 생기는 ? 코드를 대체하고자 래핑한 클래스입니다. NamedParameterJdbcTemplatesql 쿼리를 만드는 전략은 추가해야 할 파라미터가 많을 때 코드 작성을 정말 편리하게 만들어 줍니다.

 

직접 코드를 작성해보면 이 편리함을 느낄 수 있습니다.

간단하게 우테코 crew들의 정보를 관리할 수 있는 table을 만들고 entity를 생성해보겠습니다.

public class Crew {

    private Long id;
    private String name;
    private String nickname;
    private String phoneNumber;

    public Crew(Long id, String name, String nickname, String phoneNumber) {
        this.id = id;
        this.name = name;
        this.nickname = nickname;
        this.phoneNumber = phoneNumber;
    }

    public Crew(String name, String nickname, String phoneNumber) {
        this.name = name;
        this.nickname = nickname;
        this.phoneNumber = phoneNumber;
    }

    // .. getter 생략
}

그리고 NamedParameterJdbcTemplate를 사용하는 Repository 클래스를 하나 생성합니다.

@Repository
public class CrewRepository {

    private final NamedParameterJdbcTemplate jdbcTemplate;

    public CrewRepository(NamedParameterJdbcTemplate jdbcTemplate) {
        this.jdbcTemplate = jdbcTemplate;
    }
}

이제 크루 정보를 기입하고 여러 정보에 따라 크루의 데이터를 가져오는 코드를 작성해보겠습니다.

public void create(Crew crew) {
  String sql = "insert into crew (name, nickname, phone_number) values (:name, :nickname, :phoneNumber)";
  SqlParameterSource namedParameters = new BeanPropertySqlParameterSource(crew);
  jdbcTemplate.update(sql, namedParameters);
}

일반 jdbcTemplate 과 차이가 느껴지나요?

일반적인 경우에는 아래와 같은 순서로 sql 쿼리를 작성하는 데요,

  1. 입력하고자 하는 파라미터를 ?로 작성한다.
  2. 순서에 맞게 ?에 값을 할당한다.

NamedParameterJdbcTemplate를 사용하는 경우에는 위 코드처럼 SqlParameterSource의 구현체를 사용하여 간단하게 입력 파라미터를 완성시킵니다.

어떻게 완성할 수 있을까요?

    /**
     * Create a new BeanPropertySqlParameterSource for the given bean.
     * @param object the bean instance to wrap
     */
    public BeanPropertySqlParameterSource(Object object) {
        this.beanWrapper = PropertyAccessorFactory.forBeanPropertyAccess(object);
    }

위 구현체는 내부적으로 java beans에 접근하여 파라미터의 이름과 동일하게 작성된 field의 getter가 존재한다면 해당 값을 가져와 입력 파라미터에 할당할 수 있습니다.

덕분에 웹요청으로 들어온 값을 Dto 하나로 생성하여 쉽게 option에 따른 계산로직을 수행할 수도 있습니다.

public Crew findByOption(CrewDto crewDto) {
  String sql = createFilterSelectSql(crewDto);
  log.info("SQL query = {}",sql);
  SqlParameterSource namedParameters = new BeanPropertySqlParameterSource(crewDto);
  return jdbcTemplate.queryForObject(sql, namedParameters, (rs, rowNum) -> {
    return new Crew(rs.getLong("id"),
                    rs.getString("name"),
                    rs.getString("nickname"),
                    rs.getString("phone_number"));
  });
}

private String createFilterSelectSql(CrewDto crewDto) {
  StringBuilder stringBuilder = new StringBuilder();
  String sql = "select * from crew";
  stringBuilder.append(sql);
  String keyword = " where";

  if (!crewDto.isNameNull()) {
    keyword = changePrefixKeyword(sql);
    stringBuilder.append(keyword)
      .append(" name = :name");
  }

  if (!crewDto.isNicknameNull()) {
    keyword = changePrefixKeyword(sql);
    stringBuilder.append(keyword)
      .append(" nickname = :nickname");
  }

  if (!crewDto.isPhoneNumberNull()) {
    keyword = changePrefixKeyword(sql);
    stringBuilder.append(keyword)
      .append(" phone_number = :phoneNumber");
  }
  return stringBuilder.toString();
}

SqlParamterSource를 이용한다면 자바 빈즈를 사용해서 쉽게 입력 파라미터를 사용할 수 있습니다 ^^