[Spring] JdbcTemplate이란? JdbcTemplate 사용법, RowMapper란?

JdbcTemplate이란?

JdbcTemplate은 JDBC 코어 패키지의 중앙 클래스로 JDBC의 사용을 단순화하고 일반적인 오류를 방지하는데 도움이 된다. 개발자가 JDBC를 직접 사용할 때 발생하는 다음과 같은 반복 작업을 대신 처리해준다.

 

  • 커넥션 획득
  • statement를 준비하고 실행
  • 결과를 반복하도록 루프를 실행
  • 커넥션 종료, statement 및 resultset 종료
  • 트랜잭션을 다루기 위한 커넥션 동기화
  • 예외 발생 시 스프링 예외 변환기 실행

 

쉽게 말해 JdbcTemplate은 개발자가 JDBC 기술을 쉽게 사용할 수 있도록 도와주는 클래스이다.

 

 

참고)

[Spring] JDBC(Java Database Connectivity)란? JDBC 드라이버란?

 

[Spring] JDBC(Java Database Connectivity)란? JDBC 드라이버란?

JDBC의 등장 배경 애플리케이션 서버에서 DB를 연결하기 위해선 어떤 동작이 필요할까? 1. 커넥션 연결 : 주로 TCP/IP를 사용해 애플리케이션 서버와 DB서버가 연결된다. 2. SQL 전달 : 애플리케이션 서

code-lab1.tistory.com

 

 

JdbcTemplate 사용법

1. JdbcTemplate 설정

스프링에서 JdbcTemplate을 사용하기 위해서는 먼저 jdbc 라이브러리를 프로젝트에 추가해야 한다.

 

Gradle을 기준으로 설명하자면 다음과 같다.

 

//JdbcTemplate 추가
implementation 'org.springframework.boot:spring-boot-starter-jdbc'

build.gradle 파일에 위와 같은 코드를 작성해주면 된다.

JdbcTemplate은 spring-jdbc에 포함되어 있다.

 

 

2. DataSource 주입

private final JdbcTemplate jdbcTemplate;

public JdbcTemplateItemRepository(DataSource dataSource) {
	this.jdbcTemplate = new JdbcTemplate(dataSource);
}

JdbcTemplate은 DataSource를 필요로 한다. DataSource는 스프링 빈으로 등록되어 있어야 한다. 

이렇게 JdbcTemplate을 사용할 때 DataSource를 의존 관계 주입받는 방법과, JdbcTemplate을 스프링 빈으로 직접 등록하고 주입받는 방법이 있지만 전자를 관례상 많이 사용한다.

 

참고)

DataSource에 대한 이해

[Spring] 의존관계 주입(Dependency Injection), 의존성 주입, DI란?

[Spring] IoC,DI, 스프링 컨테이너(Container), 스프링 빈(Bean)이란?

 

 

3. 쿼리 작성 및 실행

스프링 JdbcTemplate 사용 방법 공식 매뉴얼이 제공하는 몇 가지 예제를 살펴보자.

 

1) queryForObject()

 

queryForObject() 인터페이스의 정의는 다음과 같다.

<T> T queryForObject(String sql, RowMapper<T> rowMapper, Object... args) throws DataAccessException;
  • sql : 실행할 sql문
  • rowMapper : 조회대상 
  • args : 파라미터들

 

이러한 queryForObject() 메서드를 사용하면 단건 조회를 할 수 있다. 이때 조회 대상이 객체가 아닌 단순 데이터라면 타입을 아래와 같이 지정해줄 수 있다.

int rowCount = jdbcTemplate.queryForObject("select count(*) from t_actor",Integer.class);

preparedStatement ("?")를 이용해 파라미터 바인딩도 할 수 있다.? 에 순서대로 파라미터가 들어가게 된다.

int countOfActorsNamedJoe = jdbcTemplate.queryForObject(
"select count(*) from t_actor where first_name = ?", Integer.class, "Joe");

 

String을 조회할 때는 아래와 같이 사용할 수도 있다.

String lastName = jdbcTemplate.queryForObject(
"select last_name from t_actor where id = ?", String.class, 1212L);

이때 단순 데이터 타입이 아닌 객체를 조회하려면 어떻게 할까?

 

여기서 RowMapper를 활용해 객체를 조회할 수 있다.

 

RowMapper란?

RowMapper는 데이터베이스의 반환 결과인 ResultSet을 객체로 변환해주는 클래스이다. 

 

순수 JDBC를 사용할 때는 객체를 조회할 때 다음과 같이 했다.

 

// 쿼리 날리기
ResultSet rs = stat.excuteQuery("SELECT * FROM Item");

// 결과값 가져오기
while(rs.next()) {
     // item 객체에 값 저장
     item = new Item();
     item.setId(rs.getInt(1));
     item.setItemName(rs.getString(2));
     item.setPrice(rs.getInt(3));
     
     // 리스트에 추가
     itemList.add(item);
}

 

ResultSet의 결과를 개발자가 직접 꺼내 객체에 담아 저장하였다. 

하지만 RowMapper를 사용하면 이러한 반복 작업을 자동화해준다.

 

RowMapper의 mapRow()라는 메서드는 아래와 같이 정의되어 있다.

T mapRow(ResultSet rs, int rowNum) throws SQLException;

ResultSet rs에 결괏값을 담아와 사용자가 원하는 객체에 담는다. rowNum은 반복되는 루프 중 현재 행의 번호를 나타낸다.

 

즉 아래와 같이 동작한다.

public Item mapRow(ResultSet rs, int rowNum) throws SQLException {
    // ResultSet 값을 Item 객체에 저장
    Item item = new Item();
    item.setId(rs.getLong("id"));
    item.setItemName(rs.getString("item_name"));
    item.setPrice(rs.getInt("price"));
    
    // item 반환
    return item;
};

 

이것을 람다식을 이용해 더 간단하게 만들고, queryForObject() 메서드에서 객체를 조회하도록 할 수 있다.

 

String sql = "select id, item_name, price from item where id= ?";

Item item = jdbcTemplate.queryForObject(sql, itemRowMapper(), id);

private RowMapper<Item> itemRowMapper() {
    return (rs, rowNum) -> {
        Item item = new Item();
        item.setId(rs.getLong("id"));
        item.setItemName(rs.getString("item_name"));
        item.setPrice(rs.getInt("price"));
        item.setQuantity(rs.getInt("quantity"));
        return item;
    };
}

 

2) query() 메서드

 

query() 메서드를 사용하면 여러 건을 조회할 수 있다. 이때도 역시 RowMapper를 이용할 수 있다.

private final RowMapper<Actor> actorRowMapper = (resultSet, rowNum) -> {
    Actor actor = new Actor();
    actor.setFirstName(resultSet.getString("first_name"));
    actor.setLastName(resultSet.getString("last_name"));
    return actor;
};

public List<Actor> findAllActors() {
    return this.jdbcTemplate.query("select first_name, last_name from t_actor", actorRowMapper);

 

3) update() 메서드

 

INSERT, UPDATE, DELETE 등 데이터를 변경하고 싶을 때는 update() 메서드를 사용할 수 있다. SQL 실행 결과에 영향받은 로우 수를 int로 반환한다.

 

등록

jdbcTemplate.update("insert into t_actor (first_name, last_name) values (?, ?)","Leonor", "Watling");

 

수정

jdbcTemplate.update("update t_actor set last_name = ? where id = ?", "Banjo", 5276L);

 

삭제

jdbcTemplate.update("delete from t_actor where id = ?", Long.valueOf(actorId));

 

 

4) execute() 메서드

 

이외에 임의의 SQL을 실행할 때는 execute() 메서드를 사용할 수 있다. 테이블을 생성하는 DDL 등에 사용할 수 있다.

jdbcTemplate.execute("create table mytable (id integer, name varchar(100))");

 

 


참고

 

1. https://www.inflearn.com/course/%EC%8A%A4%ED%94%84%EB%A7%81-db-2/dashboard

2. https://docs.spring.io/spring-framework/docs/current/reference/html/dataaccess.html#jdbc-JdbcTemplate

 

 

반응형

댓글

Designed by JB FACTORY