-
스프링 DB 데이터접근 기술 - 스프링 JdbcTemplateSpring-Boot/스프링 DB 2편 - 데이터 접근 기술 2022. 9. 5. 18:43
- SQL을 직접 사용하는 경우에 스프링이 제공하는 JdbcTemplate은 아주 좋은 선택지이다. JdbcTemplate은 JDBC를 매우 편리하게 사용할 수 있게 도와준다.
* 장점 *
- 설정의 편리함
ㆍJdbcTemplate은 `spring-jdbc` 라이브러리에 포함되어 있는데, 이 라이브러리는 스프링으로 JDBC를 사용할 때
기본으로 사용되는 라이브러리이다.
ㆍ그리고 별도의 복잡한 설정 없이 바로 사용할 수 있다
- 반복 문제 해결
ㆍJdbcTemplate은 템플릿 콜백 패턴을 사용해서, JDBC를 직접 사용할 때 발생하는 대부분의 반복 작업을 대신 처리
ㆍ개발자는 SQL을 작성하고, 전달할 파라미터를 정의하고, 응답 값을 매핑하기만 하면 된다
ㆍ우리가 생각할 수 있는 대부분의 반복 작업을 대신 처리해준다
ㆍ커넥션 획득
ㆍ`statement`를 준비하고 실행
ㆍ결과를 반복하도록 루프를 실행
ㆍ커넥션 종료, `statement`, `resultset` 종료
ㆍ트랜잭션 다루기 위한 커넥션 동기화
ㆍ예외 발생시 스프링 예외 변환기 실행
* 단점 *
- 동적 SQL을 해결하기 어렵다.
* 로그 추가
``` properties #jdbcTemplate sql log logging.level.org.springframework.jdbc=debug
* 개발을 할 때는 코드를 몇줄 줄이는 편리함도 중요하지만, 모호함을 제거해서 코드를 명확하게 만드는 것이 유지보수 관점에서 매우 중요하다 *
이름 지정 바인딩
- JdbcTemplate은 이런 문제를 보완하기 위해 `NamedParameterJdbcTemplate` 라는 이름을 지정해서 파라미터를 바인딩하는 기능을 제공한다.
- 파라미터를 전달하려면 `Map`처럼 `key`, `value` 데이터 구조를 만들어서 전달해야 한다
ㆍ여기서 `key`는 `:파라미터이름` 으로 지정한 파라미터 이름이고, `value`는 파라미터의 값이 된다.
template.update(sql, param, keyHolder);
- 다음 코드를 보면 param으로 전달하는 것을 확인
- 이름 지정 바인딩에서 자주 사용하는 파라미터 종류 3가지
ㆍMap
ㆍSqlParameterSource
ㆍMapSqlParameterSource
ㆍBeanPropertySqlParameterSource
* 1. Map *
- 단순히 `Map`을 사용
Map<String, Object> param = Map.of("id", id); Item item = template.queryForObject(sql,param, itemRowMapper());
* 2. MapSqlParameterSource *
- Map 과 유사한데, SQL 타입을 지정할 수 있는 등 SQL에 좀 더 특화된 기능을 제공
- SqlParameterSource 인터페이스의 구현체
- MapSqlParameterSource 는 메서드 체인을 통해 편리한 사용법도 제공
SqlParameterSource param = new MapSqlParameterSource() .addValue("itemName", updateParam.getItemName()) .addValue("price", updateParam.getPrice()) .addValue("quantity", updateParam.getQuantity()) .addValue("id", itemId); template.update(sql, param);
* 3. BeanPropertySqlParameterSource *
- 자바빈 프로퍼티 규약을 통해서 자동으로 파라미터 객체를 생성한다
ㆍ예 ) getXxx() → xxx()
- SqlParameterSource 인터페이스의 구현체이다
SqlParameterSource param = new BeanPropertySqlParameterSource(item); KeyHolder keyHolder = new GeneratedKeyHolder(); template.update(sql, param, keyHolder);
- BeanPropertySqlParameterSource 가 많은 것을 자동화 해주기 때문에 좋아보이지만 dto에 값이 없으면 사용할 수 없다.
private RowMapper<Item> itemRowMapper() { return BeanPropertyRowMapper.newInstance(Item.class); // camel 변환 지원 }
- `BeanPropertyRowMapper`는 `ResultSet`의 결과를 받아서 자바빈 규약에 맞추어 데이터를 변환
- 데이터베이스에서 조회한 결과 이름을 기반으로 `setId()`, `setPrice()`처럼 자바빈 프로퍼티 규약에 맞춘 메서드를 호출
* 별칭 *
- 그런데 `select item_name`의 경우 `setItem_name()` 이라는 메서드가 없기에 골치아프다
- 이런 경우 개발자가 조회 SQL을 다음과 같이 고치면 된다.
ㆍ`select item_name as itemName`
- 별칭 `as`를 사용해서 SQL 조회 결과의 이름을 변경하는 것이다.
- 이렇게 데이터베이스 컬럼 이름과 객체의 이름이 다를 때 별칭(`as`)을 사용해서 문제를 많이 해결한다.
ㆍ`JdbcTemplate`은 물론이고 `MyBatis`같은 기술에서도 자주 사용
* 관례의 불일치 *
- 자바 객체는 카멜표기법을 사용한다.
- 반면에 관계형 데이터베이스에서는 주로 언더스코어를 사용하는 스네이크표기법을 사용한다.
- `BeanPropertyRowMapper`는 언더스코어 표기법을 카멜로 자동 변환해준다.
* SimpleJdbcInsert *
this.jdbcInsert = new SimpleJdbcInsert(dataSource) .withTableName("item") .usingGeneratedKeyColumns("id"); // .usingColumns("item_name","price","quantity"); // 생략가능
- `withTableName` : 데이터를 저장할 테이블 명을 지정한다.
- `usingGeneratedKeyColumns` : key를 생성하는 PK 컬럼명을 지정
- `usingColumns` : INSERT SQL에 사용할 컬럼을 지정한다. 특정 값만 저장하고 싶을 때 사용, 생략 가능
- `SimpleJdbcInsert`는 생성 시점에 데이터베이스 테이블의 메타 데이터를 조회한다
ㆍ따라서 어떤 컬럼이 있는지 확인 가능하기에 `usingColumns` 생략 가능
JdbcTemplate 기능 정리
- JdbcTemplate
ㆍ순서 기반 파라미터 바인딩을 지원
- NamedParameterJdbcTemplate
ㆍ이름 기반 파라미터 바인디을 지원( 권장 )
- SimpleJdbcInsert
ㆍINSERT SQL을 편리하게 사용할 수 있다
- SimpleJdbcCall
ㆍ스토어드 프로시저를 편리하게 호출할 수 있다.
* 정리 *
- JdbcTemplate의 최대 단점이 바로 동적 쿼리 문제를 해결하지 못한다는 점이다.
- SQL을 자바 코드로 작성하기 때문에 SQL라인이 코드를 넘어갈 때마다 문자 더하기를 해주어야 하는 단점도 있다.
→ 동적 쿼리 문제를 해결하면서 동시에 SQL도 편리하게 작성할 수 있게 도와주는 기술이 바로 MyBatis 이다.
'Spring-Boot > 스프링 DB 2편 - 데이터 접근 기술' 카테고리의 다른 글
스프링 DB 데이터접근 기술 - 스프링데이터 JPA (0) 2022.09.22 스프링 DB 데이터접근 기술 - JPA (0) 2022.09.22 스프링 DB 데이터접근 기술 - MyBatis (0) 2022.09.17 스프링 DB 데이터접근 기술 - 테스트 (0) 2022.09.14 스프링 DB 데이터접근 기술 - 시작 (0) 2022.09.01