TIL/Spring

[SIST] Spring_days05_Spring의 DB 연동(Spring JDBC) / JdbcTemplate

야리니 2022. 7. 17. 11:40
728x90
반응형

스프링은 JDBC를 이용한 DAO 클래스를 구현할 수 있도록 다양한 기능을 지원하고 있다.

 

1) 템플릿 클래스를 통한 데이터 접근 지원

2) 의미 있는 익셉션 타입

3) 트랜잭션 처리

 

오늘은 1) 템플릿 클래스를 통한 데이터 접근 지원에 대해서 살짝 배웠기 때문에 그 내용에 대해서 정리하고자 한다.

 

1. DataSource 설정

데이터베이스 연동을 하려면 데이터베이스에 연결해야 한다.

Java에서 데이터베이스에 연결하는 방법에는 몇 가지가 있는데 그 중에서 스프링은 DataSource 방식을 사용하고 있다. 앞으로 배울 JdbcTemplate이나 JPA/하이버네이트/MyBatis 지원 기능을 사용할 경우, 데이터베이스 연결을 위해 DataSource를 설정해 주어야 한다.

 

스프링은 다음과 같이 세 가지 방식의 DataSource 설정을 지원하고 있다.

1) 커넥션 풀을 이용한 DataSource 설정

2) JNDI를 이용한 DataSource 설정

3) DriverManager를 이용한 DataSource 설정(테스트 목적)

3)은 커넥션 풀이 아니기 때문에 실제 운영 환경에서 사용할 경우 성능에 심각한 문제가 발생할 수 있으므로 테스트 목적으로만 사용할 것을 권함!

 

오늘은 3) DriverManager를 이용한 DataSource 설정(테스트 목적) 예제만 다뤄볼 것이다.

위와 같은 종류가 있다고 알고 있자! 추가로 배울 때 마다 내용을 추가할 예정!


2. 데이터베이스 연동을 위한 템플릿 클래스와 JDBC와 관련된 템플릿 클래스

데이터에 접근하는 코드는 거의 동일한 코드 구성을 갖는다.

JDBC를 사용할 경우 특정 테이블에서 데이터를 로딩하는 코드는 Connection을 생성하고 PreparedStatement, ResultSet, Connection 등의 자원을 반환하는 코드는 거의 모든 JDBC에서 중복되는 코드이다.

이런 반복되는 구조의 코드는 코드 누락 등의 실수를 유발할 수 있다. 템플렛 메서드 패턴과 전략 패턴을 함께 사용하면 이런 구조적인 중복을 줄일 수 있는데 스프링은 이미 이 두 가지 패턴이 적용된 JDBC 템플릿 클래스를 제공하고 있다. 즉, 이 템플릿 클래스를 사용하면 DB 연동할 때 항상 하는 중복되는 코딩을 제거할 수 있다.

 

> JDBC와 관련된 템플릿 클래스 4가지

1) JdbcTemplate - 기본적인 JDBC 템플릿 클래스로서 JDBC를 이용해서 데이터에 대한 접근을 제공한다.

2) NamedParameterJdbcTemplate - PreparedStatement에서 인덱스 기반의 파라미터가 아닌 이름을 가진 파라미터를 사용할 수 있도록 지원하는 템플릿 클래스

3) SimpleJdbcInsert - 데이터 삽입을 위한 인터페이스를 제공해주는 클래스

4) SimpleJdbcCall - 프로시저 호출을 위한 인터페이스를 제공해주는 클래스

 

예를 들어, JDBC를 위한 JdbcTemplate 클래스를 제공하고 있으며, 이 클래스를 사용하면 다음과 같이 try-catch-finally 블럭 및 커넥션 관리를 위한 중복되는 코드를 줄이거나 없앨 수 있다.

출처 : 웹 개발자를 위한 spring 4.0


3. JdbcTemplate 클래스를 이용한 JDBC 프로그래밍

JdbcTemplate 클래스는 SQL 실행을 위한 메서드를 제공하고 있다.

메서드를 사용하면 데이터 조회, 삽입, 수정, 삭제를 위한 SQL 쿼리를 실행할 수 있다.

JdbcTemplate 클래스를 사용하려면 JdbcTemplate 객체를 생성할 때 DataSource를 전달해주면 된다.

 

아래와 같은 DAO 클래스가 있다면

위 클래스에 대한 스프링 설정 파일은 다음과 같을 것이다.

 

다음과 같이 JdbcTemplate 클래스를 전달받도록 구현할 수도 있다.

 

DAO 클래스에서 JdbcTemplate을 프로퍼티나 생성자에서 전달받을 경우, 스프링 설정 파일에서는 다음과 같이 JdbcTemplate을 빈 객체로 생성해주면 된다.

 

3-2. JdbcTemplate 메서드

1) query() - 여러 개의 레코드를 조회할 때 사용(ex. select * from board)

List<T> query(String sql, RowMapper<T> rowMapper)

List<T> query(String sql, Object[] args, RowMapper<T> rowMapper)

List<T> query(String sql, Object[] args, int[] argTypes, RowMapper<T> rowMapper)

 

위 메서드에서 각 파라미터는 다음과 같다.

 

> sql : SQL 쿼리. 위치 기반 파라미터(물음표)를 이용하는 PreparedStatement용 쿼리를 사용할 수 있다.

> RowMapper : 조회 결과를 ResultSet으로부터 데이터를 읽어와 객체를 생성해주는 매퍼

> args : PreparedStatement를 실행할 때 사용할 파라미터 바인딩 값 목록

> argTypes : 위의 파라미터를 바인딩 할 때 사용할 SQL 타입 목록

 

객체 배열을 사용하는 대신 PreparedStatement를 이용해서 파라미터 값을 직접 지정하고 싶다면 PreparedStatement를 파라미터로 갖는 query() 메서드를 사용하면 된다.

 

List<T> query(String sql, PreparedStatementSetter setter, RowMapper<T> rowMapper)

 

SQL 쿼리를 파라미터로 사용하는 방법 대신 직접 PreparedStatement 객체를 생성하고 바인딩 파라미터를 지정해주고 싶다면 PreparedStatementCreator 타입을 파라미터로 갖는 다음 query() 메서드를 사용하면 된다.

 

List<T> query(PreparedStatementSetter setter, RowMapper<T> rowMapper)


2) queryForList() - 단일 컬럼 값을 조회할 때 사용(ex. select count(*) from board)

queryForList(String sql, Class<T> elementType)

queryForList(String sql, Object[] args, Class<T> elementType)

queryForList(String sql, Object[] args, int[] argTypes, Class<T> elementType)

 

> elementType 파라미터는 조회할 데이터 타입을 지정할 때 사용


3) queryForObject() - 단일 레코드를 조회할 때 사용(ex. select * from board where seq=1)

 

queryForObject 메서드에 전달되는 각가의 파라미터는 query() 메서드와 동일하며, 차이점이 있다면  List 대신 한 개의 객체를 리턴한다는 점이다.

주의할 점은 쿼리 실행 결과로 구한 행의 갯수가 정확하게 한 개가 아니면 익셉션을 발생시킨다.(0개 이거나 2개 이상인 경우)

 


4) update() - 삽입/수정/삭제를 위한 메서드

INSERT, UPDATE, DELETE 쿼리를 실행할 때는 update() 매서드를 사용한다.

update() 메서드도 query() 메서드와 마찬가지로 인덱스 파라미터를 위한 값을 전달받는 메서드와 그렇지 않은 메서드로 구분된다.

 

int update(String sql)

int update(String sql, Object... args)

int update(String sql, Object[] args, int[] argTypes)

int update(String sql, PreparedStatementSetter pss)

int update(PreparedStatementSetter pss)

 

update() 메서드는 쿼리 실행 결과로 변경된 행의 개수를 리턴한다.


추가 내용)

 

> RowMapper : ResultSet 에서 값을 추출하여 원하는 객체로 변환(자동으로 변환)

 

> BeanPropertyRowMapper : ResultSet -> Bean 으로 변환(자동으로 변환)

DB의 컬럼명과 bean 객체의 속성명이 일치하다면 BeanPropertyRowMapper를 이용하여 자동으로 객체변환을 할 수 있다. DB 컬럼명이 'snake_case'로 되어 있어도 'camelCase'로 선언된 클래스의 필드로 매핑된다.

 

ColumnMapRowMapper : ResultSet -> Map 으로 변환

 

Spring 3.0부터 ParameterizedBeanPropertyRowMapper와 BeanPropertyRowMapper는 동일

Spring 이 제네릭이 없는 Java 버전 < 1.5와 호환될 때 ParameterizedBeanPropertyRowMapper 추가

제네릭이 있다면 BeanPropertyRowMapper 사용하면 됨!

 

ParameterizedBeanPropertyRowMapper는 newInstance로 메서드로 객체 생성

BeanPropertyRowMapper는 new 연산자로 객체를 생성하느냐의 차이

 

조건 : 쿼리의 컬럼명과 VO의 필드명이 동일해야함


4. DriverManager로 DataSource 설정 + JdbcTemplate 템플릿 클래스 사용하는 예제

 

1) dispatcher-servlet.xml에서 DataSource 빈 객체 생성 / JdbcTemplate 빈 객체 생성 + DataSource 주입

 

2) DAO 클래스에서 JdbcTemplate 필드 생성

 

3) DAO 클래스 컨트롤러 메서드 수정

공지사항 목록 가져오는 getNotices() 메서드 수정

> new BeanPropertyRowMapper<Notice>(Notice.class) 코딩으로 ResultSet -> Bean 변환 되어진다.

 

검색한 결과의 총 레코드 수를 반환하는 getCount() 메서드 수정

 

공지사항 추가하는 insert() 메서드 수정

 

공지사항 삭제하는 delete() 메서드 수정

 

공지사항 수정하는 update() 메서드 수정

 

공지사항 상세보기 getNotice() 메서드 수정

> ParameterizedBeanPropertyRowMapper.newInstance(Notice.class) 코딩으로  ResultSet -> Bean 변환 되어진다.

 

아래 포스팅한 글 중에 컨트롤러 메서드 부분과 비교해보면 코드가 얼마나 줄었는지 확인할 수 있다.

https://yelin1217.tistory.com/333

 

[SIST] Srping_days04_Spring MVC

days03 수업은 xml 설정 파일로 빈 객체를 생성 + 조립하고 요청URL에 해당하는 컨트롤러를 검색하였다. 오늘은 컴포넌트 스캔 기능 + 애노테이션으로 매핑 처리를 해주고 어떤 클래스가 컨트롤러

yelin1217.tistory.com

 

728x90
반응형