SPRING 입문 [ 코드로 배우는 스프링 부트 ]

[스프링 입문] 섹션 6.4 스프링 DB 접근 기술 (스프링 통합 Jdbc Template)

wlalsu_u 2023. 1. 17. 22:50

6.4.1  스프링 Jdbc Template 코드 작성

 

 

앞선 섹션 6.2의 예제에서, 대부분의 코드들이 중복으로 작성되었다.

 

스프링 JdbcTemplate, MyBatis 같은 라이브러리는 JDBC API 에서의 중복 코드를 제거해준다.

 

따라서 순수 Jdbc 보다 훨씬 간결하게 코드를 작성할 수 있다는 장점이 있다.

 

(단, sql 은 직접 작성해야 한다.)

 

 

 

 

JdbcTemplate 코드를 작성해보자.

 

 

 

 

 

먼저, Jdbc Template 환경 설정의 경우, 섹션 6.3의 순수 Jdbc 설정과 동일하다.

 

buile.gradle 파일의 dependencies 에 아래의 코드를 추가로 작성한다.

 

 

implementation 'org.springframework.boot:spring-boot-starter-jdbc'
runtimeOnly 'com.h2database:h2'

 

 

 

다음으로, src  >  main  >  java  >  hello.hellospring  >  repository 폴더에

 

JdbcTemplateMemberRepository 파일을 생성하고, MemberRepository 를 구현한다.

 

 

public class JdbcTemplateMemberRepository implements MemberRepository

 

 

여기서는 JdbcTemplate 을 사용해야 하므로 아래처럼 코드를 추가한다.

 

 

private final JdbcTemplate jdbcTemplate;

 

 

 

이때, JdbcTemplate 을 인젝션 받을 수 없기 때문에,  DataSource 를 인젝션 받도록 한다.

 

 

 

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

 

 

+ 추가 )
위의 코드 처럼 생성자가 하나만 있을 때는, @Autowired 를 생략할 수 있다.

 

 

 

1) save

 

 

먼저, 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;
    }

 

 

- SimpleJdbcInsert : jdbcTemplete 을 전달받고, 테이블 명과 id 로 insert 문을 작성한다. 

 

- executeAndReturnKey 에서 key 를 전달 받는다.

 

- 전달 받은 key 를 setId 로 넣어준다.

 

 

 

2) findById

 

 

@Override
    public Optional<Member> findById(Long id){
        List<Member> result = jdbcTemplate.query("select * from member where id = ?", memberRowMapper(), id);
        return result.stream().findAny();
    }

 

 

 

- memberRowMapper() 를 두번째 파라미터에 넣어준다. (아래에 memberRowMapper 코드 작성) 

 

- List 로 반환되는 result 를 stream() 으로 바꾸고, findAny() 작성 (Optional 로 반환)

 

 

 

 

3) memberRowMapper

 

 

private RowMapper<Member> memberRowMapper(){
        return (rs, rowNum) -> {
            Member member = new Member();
            member.setId(rs.getLong("id"));
            member.setName(rs.getString("name"));
            return member;
        };
    }

 

 

- member 객체를 하나 생성한다.

 

- setId / setName 에서 resultSet 이 넘어오게 된다.

 

- member 를 반환해준다.

 

 

 

 

4) findAll

 

 

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

 

 

- memberRowMapper() 로 매핑한다.

 

 

 

 

5) findByName

 

 

@Override
    public Optional<Member> findByName(String name) {
        List<Member> result = jdbcTemplate.query("select * from member where name = ?", memberRowMapper(), name);
        return result.stream().findAny();
    }

 

 

- findById 와 동일하게 작성하되, 파라미터로 id 대신 name 을 받는다.

 

 

 

 

 

 

 

전체 코드는 다음과 같다.

 

 

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;

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

    @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;
    }

    @Override
    public Optional<Member> findById(Long id){
        List<Member> result = jdbcTemplate.query("select * from member where id = ?", memberRowMapper(), id);
        return result.stream().findAny();
    }

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

    @Override
    public Optional<Member> findByName(String name) {
        List<Member> result = jdbcTemplate.query("select * from member where name = ?", memberRowMapper(), name);
        return result.stream().findAny();
    }


    private RowMapper<Member> memberRowMapper(){
        return (rs, rowNum) -> {
            Member member = new Member();
            member.setId(rs.getLong("id"));
            member.setName(rs.getString("name"));
            return member;
        };
    }

}

 

 


 

 

6.4.2  SpringConfig 변경 / Test

 

 

SpringConfig 에서 memberRepository 의 return 값을,

 

JdbcTemplateMemberRepository 로 변경하고, dataSource 를 넣어주도록 작성한다.

 

 

 

@Bean
    public MemberRepository memberRepository() {
        return new JdbcTemplateMemberRepository(dataSource);
    }

 

 

 

 

지금까지 작성한 코드는 웹 어플리케이션을 통해 검증할 필요 없이,

 

앞서 섹션 6.3 에서 작성한 스프링 통합 test 코드를 통해 간단하게 확인할 수 있다. 

 

 

 

test 코드를 실행해보면, 다음과 같이 정상적으로 작동하는 것을 확인할 수 있다.

 

 

 

 

 

 

 

 

 

 

 

 

 

 

김영한 '스프링 입문 - 코드로 배우는 스프링 부트, 웹 MVC, DB 접근 기술' 강의를 기반으로 작성하였습니다.

https://www.inflearn.com/course/%EC%8A%A4%ED%94%84%EB%A7%81-%EC%9E%85%EB%AC%B8-%EC%8A%A4%ED%94%84%EB%A7%81%EB%B6%80%ED%8A%B8/dashboard