[인프런] 김영한님 스프링 입문 정리 [3]

DB를 이용해 테스트하기

  • @SpringBootTest : 스프링 컨테이너와 테스트를 함께 실행하는 것
  • @Transactional : 테스트 케이스에 이 어노테이션이 있으면, 테스트 시작 전에 트랜잭션을 시작하고 ,테스트 완료 후 항상 롤백한다.
    즉 , DB에 Commit을 안한다

단, @Transactional이 테스트 케이스에서만 Commit을 안하고 롤백하는 것이고 일반적인 컴포넌트 @Component에서는 롤백하지 않고 정상적으로 실행된다.

통합 테스트, 단위 테스트

  • 통합 테스트 : 실제 배포 환경과 같은 환경으로 테스트를 진행하는 것
  • 단위 테스트 : 순수 메모리 환경에서 테스트를 진행하는 것

통합 테스트의 경우 DB와 연결하고 스프링 컨테이너를 실행하는 데 있어서 시간의 손실이 발생한다.
단위 테스트 같은 경우 순수 자바 코드와 메모리로 작성한 테스트 이기 때문에 속도가 빠르다.

그래서 왠만하면 단위 테스트를 사용하도록 하자.

JdbcTemplate


사용법을 간단히 알아보도록 하자.

@Repository
public class JdbcMovieFinder implements MovieFinder {

    private JdbcTemplate jdbcTmple;

    @Autowired
    public JdbcMovieFinder(DataSource dataSource) {
        this.jdbcTemplate = new JdbcTemplate(dataSource);
    }

}

JdbcTemplate 객체에 DI하기 위해 연관 관계를 찾아 스프링 컨테이너가 주입해준다.

int rowCount = 
this.jdbcTmple.queryForObject
("select count(*) from t_actor", Integer.class);
(sql문, 리턴할 인스턴스의 형태 혹은 자료형, 혹은 RowMapper , ?에 들어갈 값)

예전에 jdbc driver로 jdbc를 사용해 본 적이 있다면 ?에 들어갈 값이 무엇인지 알 수 있을 것이다.

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

pstmt.setString(1, "Joe")와 같은 의미다.

객체 같은 경우는 이렇게 가져오면 된다.

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

RowMapper 는 제네릭 인터페이스 이므로 구현체를 만들어야 한다.
T를 반환해주는 mapRow를 구현하면 될 것 같다.

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

이렇게 RowMapper를 생성해도 되고 람다로 생성하면 더 간결해진다.

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

출처

JPA

현재는 간략하게 설명하지만 정말 정리가 잘 된 velog가 있어 나중에 봐야겠다.
JPA 기본편 정리 (tmdgh0221님의 velog)

JPA란?

  • JPA (Java Persistence API) 는 자바 진영의 ORM 표준 기술이다.

JPA가 동작하는 그림을 보면 이렇다.

실제적으로 개발자는 JDBC API를 사용하지 않고 값을 넘겨주기만 하면 JPA가 중간에서 동작해 쿼리문을 만들어 DB로 전달한다.

ORM이란? (객체 관계 매핑)

  • ORM (Object-relational mapping)은 데이터베이스와 객체 지향 프로그래밍 언어 간의 호환되지 않는 데이터를 변환하는 프로그래밍 기법이다.
  • 객체 관계 매핑 기법을 통해 객체와 데이터베이스를 마치 자료구조 처럼 사용 가능하다.

JPA를 사용하는 이유

  • SQL과 데이터 중심의 설계에서 객체 중심의 설계로 전환할 수 있다.
  • 개발 생산성을 크게 높일 수 있다.

스프링 데이터 JPA

JPA 같은 경우는 EntityManager의 인스턴스를 사용해 영속화하고
JPQL문을 만들어 사용했다.
스프링 데이터 JPA는 이를 더 쉽게 사용할 수 있도록 해준다

주의 : 스프링 데이터 JPA는 JPA를 좀 더 쉽게 사용할 수 있게 해주는 기술이다.

사용 방법

Repository 컴포넌트 인터페이스에 JpaRepository<Entity, ID>를 구현한다.

public interface SpringDataJpaMemberRepository extends 
JpaRepository<Member, Long>, MemberRepository{
    // JPQL select m from Member m where m.name = ?
    Optional<Member> findByName(String name);
}

여기서 MemberRepository는 기존에 우리가 만들었던 구현해야할 메서드가 있는 인터페이스이고 JpaRepository가 바로 스프링 데이터 JPA 인터페이스이다.

스프링 데이터 JPA 제공기능

  • 인터페이스를 통한 기본적인 CRUD
  • findByName(), findByEmail, count처럼 메서드 이름만으로 조회 기능 제공
  • 페이징 기능 자동 제공

참고 : 실무에서는 JAP와 스프링 데이터 JPA를 기본으로 사용하고, 복잡한 동적 쿼리는 Querydsl이라는 라이브러리를 사용하면 된다.

나는 그저 스프링 데이터 JPA를 쓴 것 같다.
이번 기회에 JPA에 대해서 좀 더 깊게 들어가고 그 다음에 Node.Js를 배워야 겠다.

좋은 웹페이지 즐겨찾기