Spring/스프링 입문

[스프링 입문] 06. 스프링 DB 접근 기술 - 스프링 JdbcTemplate

HSY_mumu 2022. 4. 29. 17:04
728x90

(인프런) 김영한님의 스프링 입문 - 코드로 배우는 스프링 부트, 웹 MVC, DB 접근 기술을 공부하고 리뷰한 글입니다.

 

스프링 DB 접근 기술 4가지 방식대로 차례로 진행할 예정이다.

1. 순수 JDBC

2. JDBCTemplate

3. JPA

4. 스프링 데이터 JPA


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

1) repository 패키지에 JdbcTemplateMemberRepository 클래스 생성

2) JdbcTemplateMemberRepository 코드 작성

 

1. 생성자(Constructor)

public class JdbcTemplateMemberRepository implements MemberRepository{

    private final JdbcTemplate jdbcTemplate;

    // 생성자가 1개면 @Autowired 생략O
    // 스프링이 자동으로 dataSource 인젝션을 해줌
    public JdbcTemplateMemberRepository(DataSource dataSource) {
        jdbcTemplate = new JdbcTemplate(dataSource);
    }
    ...
}

 

2. memberRowMapper()

쿼리 결과를 RowMapper로 맵핑하여 원하는 자바 객체로 변환해주는 함수다.

// 쿼리 결과를 RowMapper로 맵핑해주는 함수
// 쿼리 결과 값(로우값)들을 RowMapper를 이용해 ResultSet을 자바 객체로 변환
private RowMapper<Member> memberRowMapper() {
    // 람다식으로 변경
    return (rs, rowNum) -> {
        // member 객체를 생성해 쿼리에서 가져온 결과(resultSet)를 맵핑
        Member member = new Member();
        member.setId(rs.getLong("id")); // resultSet의 column이 id인 값을 long으로 가져와 id에 대입
        member.setName(rs.getString("name"));   // resultSet의 column이 name인 값을 String으로 가져와 name에 대입
        return member;  // member 객체 반환
    };
    /*
    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;
        }
    }
     */
}
  • getLong("컬럼명"): DB의 컬럼명에 해당하는 값을 Long으로 반환
  • getString("컬럼명"): DB의 컬럼명에 해당하는 값을 String으로 반환
  • ResultSet: 쿼리 결과를 담고 있는 객체

3. findAll()

    // DB에 저장된 모든 member들을 리스트로 반환하는 함수
    @Override
    public List<Member> findAll() {
        // DB에 저장된 모든 member를 리스트로 반환
        return jdbcTemplate.query("select * from member", memberRowMapper());
    }

 

4. findById()

    // 해당 id를 가진 member를 Optional로 반환하는 함수
    @Override
    public Optional<Member> findById(Long id) {
        // DB의 id(column)이 파라미터 id 값과 같은 member를 찾은 결과를 리스트로 저장
        List<Member> result = jdbcTemplate.query("select * from member where id = ?", memberRowMapper(), id);
        return result.stream().findAny();   // 리스트에 있는 member 값을 Optional로 반환
    }

 

5. findByName()

    // 해당 name을 가진 member를 Optional로 반환하는 함수
    @Override
    public Optional<Member> findByName(String name) {
        // DB의 name(column)이 파라미터 name 값과 같은 member를 찾은 결과를 리스트로 저장
        List<Member> result = jdbcTemplate.query("select * from member where name = ?", memberRowMapper(), name);
        return result.stream().findAny();   // 리스트에 있는 member 값을 Optional로 반환
    }

 

 

6. 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;
}

 

7. 전체 코드

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.sql.ResultSet;
import java.sql.SQLException;
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;

    // 생성자가 1개면 @Autowired 생략O
    // 스프링이 자동으로 dataSource 인젝션을 해줌
    public JdbcTemplateMemberRepository(DataSource dataSource) {
        jdbcTemplate = new JdbcTemplate(dataSource);
    }

    // 파라미터로 들어온 member를 DB에 삽입하는 함수
    @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;
    }

    // 해당 id를 가진 member를 Optional로 반환하는 함수
    @Override
    public Optional<Member> findById(Long id) {
        // DB의 id(column)이 파라미터 id 값과 같은 member를 찾은 결과를 리스트로 저장
        List<Member> result = jdbcTemplate.query("select * from member where id = ?", memberRowMapper(), id);
        return result.stream().findAny();   // 리스트에 있는 member 값을 Optional로 반환
    }

    // 해당 name을 가진 member를 Optional로 반환하는 함수
    @Override
    public Optional<Member> findByName(String name) {
        // DB의 name(column)이 파라미터 name 값과 같은 member를 찾은 결과를 리스트로 저장
        List<Member> result = jdbcTemplate.query("select * from member where name = ?", memberRowMapper(), name);
        return result.stream().findAny();   // 리스트에 있는 member 값을 Optional로 반환
    }

    // DB에 저장된 모든 member들을 리스트로 반환하는 함수
    @Override
    public List<Member> findAll() {
        // DB에 저장된 모든 member를 리스트로 반환
        return jdbcTemplate.query("select * from member", memberRowMapper());
    }

    // 쿼리 결과를 RowMapper로 맵핑해주는 함수
    // 쿼리 결과 값(로우값)들을 RowMapper를 이용해 ResultSet을 자바 객체로 변환
    private RowMapper<Member> memberRowMapper() {
        // 람다식으로 변경
        return (rs, rowNum) -> {
            // member 객체를 생성해 쿼리에서 가져온 결과(resultSet)를 맵핑
            Member member = new Member();
            member.setId(rs.getLong("id")); // resultSet의 column이 id인 값을 long으로 가져와 id에 대입
            member.setName(rs.getString("name"));   // resultSet의 column이 name인 값을 String으로 가져와 name에 대입
            return member;  // member 객체 반환
        };
        /*
        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;
            }
        }
         */
    }
}

2. JdbcTemplate을 사용하도록 스프링 설정 변경

1. SpringConfig 파일 설정 변경

dataSource를 Jdbc로 연결하지 않고 JdbcTemplate으로 연결하도록 코드를 수정한다.

package hello.hellospring;

import hello.hellospring.repository.JdbcMemberRepository;
import hello.hellospring.repository.JdbcTemplateMemberRepository;
import hello.hellospring.repository.MemberRepository;
import hello.hellospring.repository.MemoryMemberRepository;
import hello.hellospring.service.MemberService;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import javax.sql.DataSource;

@Configuration
public class SpringConfig {
    private final DataSource dataSource;
    public SpringConfig(DataSource dataSource) {
        this.dataSource = dataSource;
    }

    // 스프링 빈에 등록
    @Bean
    public MemberService memberService() {
        return new MemberService(memberRepository());   // 의존 관계 설정
    }
    // 나중에 DB가 정해지면 바뀔 부분
    @Bean
    public MemberRepository memberRepository() {
        //return new MemoryMemberRepository();
        //return new JdbcMemberRepository(dataSource);    // JdbcMemberRepository가 dataSource 사용
        return new JdbcTemplateMemberRepository(dataSource); // JdbcTempalteRepository가 dataSource 사용
    }

}

 

728x90