본문 바로가기
Java/Spring입문

Spring 입문(13) 스프링 DB 접근 기술: 스프링 Jdbc Template

by 이쟝 2023. 5. 5.
인프런의 김영한님의 스프링입문 강의를 듣고 정리한 내용입니다.
스프링 입문 강의
1. H2 데이터베이스 설치
2. 순수 Jdbc(스프링 통합테스트)
3. 스프링 Jdbc Template
4. JPA
5. 스프링 데이터 JPA

3. 스프링 Jdbc Template 

순수 Jdbc와 동일한 환경설정을 하면 된다.(build.gradle 파일에 관련 라이브러리 추가)

스프링 JdbcTemplateMyBatis 같은 라이브러리는 순수 JDBC API에서의 반복 코드를 대부분 제거해준다. (단 SQL은 직정 작성해야 한다.)

2번에서 순수JDBC를 사용해서 구현한 JbdcMemberRepositiryJdbcTemplate라이브러리를 사용해 더 간단하게 구현할 수 있다. 

 

3-1. 스프링 JdbcTemplate 회원 레포지토리

src > main > java > hello > hellospring > repository > JdbcTemplateMemberRepository 클래스 생성
package hello.hellospring.repository;

import hello.hellospring.domain.Member;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.jdbc.core.namedparam.MapSqlParameterSource;
import org.springframework.jdbc.core.simple.SimpleJdbcInsert;

import javax.sql.DataSource;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;

public class JdbcTemplateMemberRepository implements MemberRepository {
    
    private final JdbcTemplate jdbcTemplate; // JdbcTmeplate을 사용하기 위한 객체 생성

	 // 생성자
    public JdbcTemplateMemberRepository(JdbcTemplate jdbcTemplate) {
        this.jdbcTemplate = jdbcTemplate;
    }

    @Override
    public Member save(Member member) {
        return null;
    }

    @Override
    public Optional<Member> findById(Long id) {
        return Optional.empty();
    }

    @Override
    public Optional<Member> findByName(String name) {
        return Optional.empty();
    }

    @Override
    public List<Member> findAll() {
        return null;
    }
}

 

생성자에서 DataSource를 인자로 받는다. 

jdbcTemplate을 사용하기 위해 생성자에서 dataSource를 받아 jdbcTemplate을 생성할 때 이를 인자로 넘겨주고 jdbcTemplate 객체를 생성한다. 이때 생성자가 하나이기 때문에 스프링 빈으로 등록이 될 때 생략 가능하다. 

    private final JdbcTemplate jdbcTemplate;

    //@Autowired 
    public JdbcTemplateMemberRepository(DataSource dataSource) {
        jdbcTemplate = new JdbcTemplate(dataSource);
    }

 

findById(Long id), findByName(String name) findAll( )

    @Override
    public Optional<Member> findById(Long id) {
        List<Member> result = jdbcTemplate.query("select * from member where id = ?", memberRowMapper(), id);
        return result.stream().findAny();
    }
	
    
    private RowMapper<Member> memberRowMapper() { //import org.springframework.jdbc.core.RowMapper;
       return (rs, rowNum) -> { 
            Member member = new Member();
            member.setId(rs.getLong("id"));
            member.setName(rs.getString("name"));
           return member;
       };
    }
    
    @Override
    public Optional<Member> findByName(String name) {
        List<Member> result = jdbcTemplate.query("select * from member where name = ? ", memberRowMapper(), name);
        return result.stream().findAny();
    }

    @Override
    public List<Member> findAll() {
        return jdbcTemplate.query("select * from ", memberRowMapper());
    }

 

더보기

- memberRowMapper( ): 이전에 중복되었던 코드 부분으로 회원 객체를 생성하고, 반환된 결과 값을 세팅해 반환한다.

- 중복되는 코드를  memberRowMapper( ) 메서드로 작성하고, jdbcTemplate 라이브러리를 사용해 이를 sql과 함께 쿼리문을 넘겨줘서 sql의 결과를 RowMapper를 통해서 맵핑된 뒤에 List 형태로 받는다. 

 

[원래 코드]  람다식으로 작성: alt + Enter => replace w Lamda

	private RowMapper<Member> memberRowMapper() {
        return new RowMapper<Member>() { 
            @Override
            public Member mapRow(ResultSet rs, int rowNum) throws SQLException {
                Member member = new Member();
                member.setId(rs.getLong("id"));
                member.setName(rs.getString("name"));
                return member;
            }
        };
    }

 

Save( )

    @Override
    public Member save(Member member) {
        SimpleJdbcInsert jdbcInsert = new SimpleJdbcInsert(jdbcTemplate);
        jdbcInsert.withTableName("member").usingGeneratedKeyColumns("id");

        Map<String, Object> parameters =  new HashMap<>();
        parameters.put("name",member.getName());

        Number key = jdbcInsert.executeAndReturnKey(new MapSqlParameterSource(parameters));
        member.setId(key.longValue());
        return member;
    }
더보기

jdbcTemplate을 simpleJdbcInsert의 매개변수로 받아서 테이블 이름, 안에들어갈 매개변수를 정의하면 쿼리문을 자동으로 만들어준다. 

3-2. 구현체를 사용하도록 설정(SpringConfig) 

src > main > java > hello > hellospring > service > SpringConfig

순수 JDBC에서 했던 것처럼 memberRepository에 return값을 추가해준다. 
    @Bean
    public MemberRepository memberRepository(){
        //return new MemoryMemberRepository();
        //return new JdbcMemberRepository(dataSource);
        return new JdbcTemplateMemberRepository(dataSource);
    }

기존에 JdbcMemberRepository 구현체를 사용하던 코드를 주석 처리하고, JdbcTemplateMemberRepository를 사용하도록 변경하고, dataSource를 넘겨준다. 

3-3. 수정을 마치고, 프로젝트를 실행한다. 

DB까지 연동해서 test하는 통합 테스트 코드를 작성했기 때문에, 웹 애플리케이션을 직접 실행해서 회원가입, 조회를 할 필요 없이 MemberServiceIntegrationTest코드를 실행해서 테스트를 진행한다!!