< Go Back

[SPRING] NamedParameterJdbcTemplate

Spring

파라미터 바인딩의 순서를 꼭 맞춰줘야 하는 [[JdbcTemplate]]과는 다르게 파라미터의 이름을 명시하여 바인딩할 수 있는 JdbcTemplate이다.

설정

JdbpTemplate과 마찬가지로 spring-jdbc라이브러리에 기본으로 포함되어 있으므로 스프링을 이용해 JDBC를 사용한다면 별도의 설정 없이 바로 사용할 수 있다.

사용

파라미터 바인딩에 ?를 사용하는 JdbcTemplate과는 다르게 :paramName 형태의 명시적 바인딩을 사용한다.

준비

생성자에 DataSource 구현체를 넘겨주어 NamedParameterJdbcTemplate을 생성한다.

NamedParameterJdbcTemplate template = new NamedParameterJdbcTemplate(dataSource);

Select

바인딩할 파라미터를 순서에 맞게 넘겨주면 됐던 JdbcTemplate API와는 다르게 파라미터를 Map<String, Object> 형태로 넘겨주어야 한다.

String sql = "select id, item_name, price from item where id = :id"
RowMapper<Item> rowMapper = BeanPropetyRowMapper.newInstance(Item.class);
Map<String, Object> paramMap = Map.of("id", id);

try {
	Item item = template.queryForObject(sql, paramMap, rowMapper);
	// do something with item
} catch (EmptyResultDataAccessException e) {
	// catch when there is no data
}

또다른 차이점은 RowMapper<T> 대신에 BeanPropertyRowMapper를 사용했다는 것이다. BeanPropertyRowMapper는 자바빈 클래스에 맞게 자동으로 결과를 바인딩해주는 RowMapper<T>이다.

[!info] 관례의 불일치 자바빈 규칙에서 프로퍼티는 카멜케이스로 표기하지만, 데이터베이스 칼럼 이름은 보통 스네이크케이스로 표기된다. BeanPropertyRowMapper는 이런 관례의 불일치를 자동으로 해결해준다.(예: item_name -> setItemName() 호출) 만약 칼럼 이름이 자바빈 프로퍼티와 완전히 이름이 다르다면 SQL에서 AS 키워드로 칼럼 이름을 알맞게 변환시켜주면 된다.

Insert

insert는 저장할 빈 객체의 속성들을 모두 파라미터로 바인딩해줘야 하는 경우가 많다. select처럼 파라미터 맵을 만들어서 바인딩을 할 수도 있지만, BeanPropertySqlParameterSource를 사용하면 [[JavaBean]]에서 파라미터를 가져오는 코드를 훨씬 간소화시킬 수 있다.

String sql = "insert into item(item_name, price) " + 
			"values (:itemName, :price)";
SqlParameterSource param = new BeanPropertySqlParameterSouce(item);
KeyHolder keyHolder = new GeneratedKeyHolde();
template.update(sql, param, keyHolder);

Long key = keyHolder.getKey().longValue();
// do something with key

이 경우 자동생성 키를 받아오는 훨씬 간편한 API를 사용할 수 있으므로 일반 JdbcTemplate을 사용하는 것 보다 좀더 간편하고 좋은 방식이다.

하지만 이것보다 더 간편한 방식도 있다. [[SimpleJdbcInsert]]를 이용하면 sql을 작성할 필요 없이 빈 오브젝트의 값을 인서트하고 자동생성 키 값도 받아올 수 있다.

Update

insert에서 사용한 BeanPropertySqlParameterSource는 자바 빈에서 파라미터를 자동으로 가져오는 SqlParameterSource의 구현체이다. 하지만 값을 업데이트하는 경우에는 이 구현체를 사용하기가 조금 어려운데, 보통 업데이트는 WHERE문을 포함하여 조건 파라미터를 함께 넘겨줘야 하는 경우가 많기 때문이다.

이런 경우에는 MapSqlParameterSource를 사용하여 직접 파라미터값을 지정해주면 된다.

String sql = "update item " + 
			"set item_name=:itemName, price=:price" + 
			"where id=:id";
SqlParameteSource param = new MapSqlParameterSource()
							.addValue("itemName", updateParam.getItemName())
							.addValue("price", updateParam.getPrice())
							.addValue("id", id);
template.update(sql, param);