1. JdbcTemplate을 사용했을 때, 발생하는 문제점
JdbcTemplate을 사용하면 순수 Jdbc를 사용할 때 해야하는 여러 작업들을 스프링이 대신 해준다.
순수 Jdbc를 사용하면 Connection, Statement, ResultSet을 가져오는 것부터 리소스 해제까지 해야하며,
SQL Exception까지 직접 try-catch 해야하는 번거로움이 있다.
JdbcTemplate은 이러한 작업들을 대신 처리하고, 개발자들은 애플리케이션 개발에 좀 더 집중할 수 있다.
하지만 이러한 JdbcTemplate에서도 약간의 단점이 하나 있었다.
Jdbc 기술을 사용한다면 SQL 문을 개발자가 직접 작성해야 한다. 즉 SQL문이 조작될 경우, 이에 대응하기가 어렵다.

다음과 같이 특정 테이블에 데이터를 삽입하기 위한 SQL문을 작성하여 쿼리를 날렸을 때,
DB에서 생성된 ID 값을 가져오기 위해 KeyHolder를 사용하였다.
또한 SQL 문에서 동적으로 파라미터를 바인딩하는 부분은 ? 로 처리되었다.
2. JdbcTemplate의 문제점 : SQL 문이 변경된다면?
위 사진처럼 INSERT 문의 영향을 받는 name, date, time 컬럼과
바인딩하는 코드의 컬럼 순서가 일치하면 문제가 되지 않는다.
하지만 누군가 SQL문을 조작하여 컬럼의 순서가 바뀐다면 어떻게 될까?


안타깝게도 컴파일 시점에서 타입 불일치를 발견하지 못하며 런타임 시에 예외가 발생한다.
이처럼 임의로 SQL문을 변경(추가, 삭제, 수정)할 경우, 코드 상에서 대응이 어려운 것이 JdbcTemplate의 단점이다.
3. NamedParameterJdbcTemplate를 활용하기


NamedParameterJdbcTemplate은 바인딩할 파라미터 부분을 ?로 처리하지 않고, 이름을 부여하는 방식을 제공한다.

JdbcTemplate을 사용했을 때는 ?로 처리했던 부분이 :파라미터로 지정된 걸 확인할 수 있다.
이렇게 :파라미터 지정을 했다면, 이 파라미터에 해당하는 값들을 넣어줘야 한다.
공식문서에서는 값을 지정하는 세 가지 방법을 소개한다.
1. Map 컬렉션 사용

쿼리문에 ? 대신 사용한 :파라미터의 파라미터를 key 값으로 하는 Map을 생성한다.
당연히 value는 쿼리문에 들어가야 하는 실제 값이 된다.
2 - 1. SqlParameterSource의 MapSqlParameterSource 구현체 사용

NamedParameterJdbcTemplate은 파라미터 소스로 SqlParameterSource 인터페이스를 사용할 수 있다.
구현체 중 하나인 MapSqlParameterSource는 말그대로 Map 기반의 파라미터 소스를 갖는 객체이다.

기존의 Map 컬렉션을 사용할 수도 있지만, 이 방식을 사용하면 메서드 체이닝을 통해 여러 파라미터를 추가할 수 있다.
// Map 컬렉션 사용
Map<String, String> namedParameters = Collections.singletonMap("first_name", firstName);
// MapSqlParameterSource 사용
SqlParameterSource namedParameters = new MapSqlParameterSource()
.addValue("first_name", firstName)
.addValue("second_name", secondName);
2 - 2. SqlParameterSource의 BeanPropertySqlParameterSource 구현체 사용
또 다른 구현체로는 빈 프로퍼티 규약을 활용한 BeanPropertySqlParameterSource를 사용할 수 있다.
이는 자바 빈 프로퍼티 규약을 따르는 클래스(private 멤버 변수와 getter / setter가 있는 클래스)의 인스턴스를
래핑하고 여기에 있는 프로퍼티를 getter 메서드를 통해 접근하여 ParameterSource로 활용한다.


BeanPropertySqlParamterSource 생성자에 JavaBean 객체를 넣으면 자동으로 ParameterSource가 완성된다.
2-1처럼 별도로 key-value를 넣지 않아도 된다. 대신에 JavaBean 클래스에 없는 프로퍼티에 해당하는 컬럼을 파라미터로 추가해야 한다면 1 또는 2-1을 통해 직접 추가해야 한다. (ex. Reservation 클래스에 없는 "age"라는 컬럼을 추가할 경우)

또한 BeanPropertySqlParameterSource은 Record 타입도 지원한다. 물론 쿼리문에 바인딩하는 파라미터 이름과 Record 클래스의 필드 이름은 같아야 한다. (단, Record의 getter는 필드이름이 XXX 일 때, getXXX가 아닌 XXX임.)

4. SimpleInsertJdbc를 활용하여 INSERT 문 간소화
NamedParamterJdbcTemplate를 사용하더라도 INSERT 된 데이터의 ID를 가져오려면 KeyHolder를 사용해야 한다.
하지만 SimpleInsertJdbc를 사용하면 JdbcTemplate을 사용할 때, INSERT 관련 메서드를 간단하게 할 수 있다.


SimpleInsertJdbc의 좋은 점은 개발자가 직접 INSERT 쿼리문을 작성하지 않아도 된다는 점이다.
이미 INSERT 문에 사용되는 파라미터는 앞선 방식대로 SqlParameterSource로 가져오고 있으며,
INSERT의 대상이 되는 테이블은 생성자에서 이미 지정했기 때문에 추가로 INSERT 문을 작성하지 않아도 된다.
JdbcTemplate 관련 공식 사이트
Using the JDBC Core Classes to Control Basic JDBC Processing and Error Handling :: Spring Framework
SQLExceptionTranslator is an interface to be implemented by classes that can translate between SQLExceptions and Spring’s own org.springframework.dao.DataAccessException, which is agnostic in regard to data access strategy. Implementations can be generic
docs.spring.io
BeanPropertySqlParameterSource 공식 깃허브
spring-framework/spring-jdbc/src/main/java/org/springframework/jdbc/core/namedparam/BeanPropertySqlParameterSource.java at main
Spring Framework. Contribute to spring-projects/spring-framework development by creating an account on GitHub.
github.com
JdbcTemplate 학습에 도움되는 강의
https://www.inflearn.com/course/%EC%8A%A4%ED%94%84%EB%A7%81-db-2/dashboard
스프링 DB 2편 - 데이터 접근 활용 기술 | 김영한 - 인프런
김영한 | 백엔드 개발에 필요한 DB 데이터 접근 기술을 활용하고, 완성할 수 있습니다. 스프링 DB 접근 기술의 원리와 구조를 이해하고, 더 깊이있는 백엔드 개발자로 성장할 수 있습니다., 백엔드
www.inflearn.com
'Spring Framework > Spring Boot' 카테고리의 다른 글
[JPA] 스프링 Data JPA 기술을 공부하며 배운 내용 정리 (0) | 2024.08.14 |
---|---|
[JPA] 스프링 JPA 기술을 공부하며 배운 내용 정리 (2) (0) | 2024.08.03 |
[JPA] 스프링 JPA 기술을 공부하며 배운 내용 정리 (1) (0) | 2024.08.03 |
멋사 미션을 하며 스프링 부트 예외처리에 대해 알게 된 내용들 (0) | 2024.05.14 |
관심사의 분리, 의존관계 주입(DI) (0) | 2022.12.30 |