[SpringBoot/Java/06.H2 데이터베이스 설치&통합 테스트&JdbcTemplate]

안지은·2023년 2월 5일
0

H2 데이터베이스 파일 생성 방법

  1. JDBC URL을 아래와 같이 변경한다. (최초 한 번만 실행)
  2. ~/test.mv.db 파일이 생성된 것을 확인한다.
  3. 이후부터는 아래와 같이 jdbc:h2:tcp://localhost/~/test 이런식으로 접속한다.

테이블 생성하기

create table member
(
     id bigint generated by default as identity,
     name varchar(255),
     primary key (id)
);
  • bigint - JAVA에서 long 타입
  • generated by default as identity - id 값을 따로 설정하지 않고(null) INSERT Query를 날리면 그때 id의 값을 자동으로 세팅.
  • primary key는 id
insert into member(name) values('spring')

참고 : sql 디렉토리 안에 ddl.sql 파일을 만들어 sql문을 관리

💡 스프링 통합 테스트와 단위 테스트

스프링 컨테이너와 DB까지 연결한 통합 테스트이다.

  • @SpringBootTest : 스프링 컨테이너와 테스트를 함께 실행한다.
  • @Transactional : 테스트 케이스에 이 애노테이션이 있으면, 테스트를 실행할 떼 트랜잭션을 먼저 실행하고, db에 데이터를 insert한 다음에 테스트가 끝나면 db에 있는 data를 깔끔하게 지워준다.(롤백) 따라서 테스트가 끝난 후 db를 확인하면 데이터가 남아있지 않아 다음 테스트에 영향을 끼치지 않는다.

트랜잭션이란? - db의 상태를 변경시키기 위해 수행하는 작업 단위이다. db의 상태를 변경시킨다는 이야기는 SELECT, UPDATE, INSERT, DELETE 와 같은 행동을 뜻한다.

참고로 단위 테스트란 이전에 진행한 순수한 자바 코드로 이루어진 최소한의 단위로 진행하는 테스트이다. 가급적이면 스프링 컨테이너를 올릴 필요 없이 단위단위로 쪼개서 테스트를 진행하는 것이 좋다.

💡 스프링 JdbcTemplate

JdbcTemplate과 MyBatis 같은 라이브러리는 순수 JDBC에서의 반복 코드를 대부분
제거해주지만 SQL은 직접 작성해야 한다

build.gradle 파일에 jdbc, h2 데이터베이스 관련 라이브러리 추가

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

resources/application.properties에 스프링 부트 데이터베이스 연결 설정 추가

spring.datasource.url=jdbc:h2:tcp://localhost/~/test
spring.datasource.driver-class-name=org.h2.Driver
spring.datasource.username=sa

JdbcTemplateMemberRepository.java

package hello.hellospring.repository;

import hello.hellospring.domain.Member;
import org.springframework.beans.factory.annotation.Autowired;
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 {

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

    private final JdbcTemplate jdbcTemplate;

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

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

        //member id 등록
        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();  //Optional로 반환
    }

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

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

    //데이터베이스의 반환 결과인 ResultSet을 객체(member)로 변환
    private RowMapper<Member> memberRowMapper() {
        return (rs, rowNum) -> {   //결과를 rs에 받음. 
            Member member = new Member();
            member.setId(rs.getLong("id"));
            member.setName(rs.getString("name"));
            return member;
        };
    }
}
  • RowMapper : 데이터베이스의 반환 결과인 ResultSet을 객체로 변환해주는 클래스
profile
공부 기록용

0개의 댓글