단, @Transactional
이 테스트 케이스에서만 Commit을 안하고 롤백하는 것이고 일반적인 컴포넌트 @Component
에서는 롤백하지 않고 정상적으로 실행된다.
통합 테스트의 경우 DB와 연결하고 스프링 컨테이너를 실행하는 데 있어서 시간의 손실이 발생한다.
단위 테스트 같은 경우 순수 자바 코드와 메모리로 작성한 테스트 이기 때문에 속도가 빠르다.
그래서 왠만하면 단위 테스트를 사용하도록 하자.
사용법을 간단히 알아보도록 하자.
@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;
};
}
현재는 간략하게 설명하지만 정말 정리가 잘 된 velog가 있어 나중에 봐야겠다.
JPA 기본편 정리 (tmdgh0221님의 velog)
JPA가 동작하는 그림을 보면 이렇다.
실제적으로 개발자는 JDBC API를 사용하지 않고 값을 넘겨주기만 하면 JPA가 중간에서 동작해 쿼리문을 만들어 DB로 전달한다.
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 인터페이스이다.
참고 : 실무에서는 JAP와 스프링 데이터 JPA를 기본으로 사용하고, 복잡한 동적 쿼리는 Querydsl이라는 라이브러리를 사용하면 된다.
나는 그저 스프링 데이터 JPA를 쓴 것 같다.
이번 기회에 JPA에 대해서 좀 더 깊게 들어가고 그 다음에 Node.Js를 배워야 겠다.