- 리포지토리 인터페이스를 만들 때 사용하던 JpaRepository 는 Spring Data JPA 의 영역이다.
- JpaRepository 는 PagingAndSortingRepository 를 상속하고 있으며 이 부터 Spring Data Common 의 영역이다.
- PagingAndSortingRepository 는 페이징 기능과 소팅 기능을 제공하며 CrudRepsitory를 상속하고 있다.
- CrudRepository 는 기본적인 CRUD 기능을 정의하고 있으며 Repository 를 상속하고 있다.
- Repository 인터페이스는 마커 인터페이스이며 실질적 기능은 없고 마커용일 뿐이다.
Repository 인터페이스를 제외하고 CrudRepository 부터는 @NoRepositoryBean 이 붙어있으며, 해당 인터페이스가 실제 Repository 가 아님을 선언해놓은 것이다.
/**
* JPA specific extension of {@link org.springframework.data.repository.Repository}.
*
* @author Oliver Gierke
* @author Christoph Strobl
* @author Mark Paluch
*/
@NoRepositoryBean
public interface JpaRepository<T, ID> extends PagingAndSortingRepository<T, ID>, QueryByExampleExecutor<T> {
/*
* (non-Javadoc)
* @see org.springframework.data.repository.CrudRepository#findAll()
*/
@Override
List<T> findAll();
...
@DataJpaTest 가 선언되어 있으며, 인 메모리 데이터베이스인 h2 의존이 있을 때 테스트시 인메모리 데이터베이스가 실행되며, 사용 중인 DB 에는 영향을 미치지 않게된다.
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<scope>test</scope>
</dependency>
@RunWith(SpringRunner.class)
@DataJpaTest
public class PostRepositoryTest {
...
}
- @Rollback 없이 테스트를 진행하면 insert 작업이 일어나지 않고 시퀀스 값만 가져와 테스트를 끝낸다.
- 이는 @DataJpaTest 에 붙어있는 @Transactional 때문인데, Test 코드에 @Transational 이 붙으면 모든 테스트는 자동으로 롤백된다.
- JPA가 롤백될 테스트에 대해서 insert 할 필요성이 없다고 판단하여 insert 작업을 실행하지 않은 것이다.
- 롤백을 진행하지 않기 위해서는@Rollback 어노테이션에 false 값을 주면 되겠다.
@RunWith(SpringRunner.class)
@DataJpaTest
public class PostRepositoryTest {
@Autowired
private PostRepository postRepository;
@Test
@Rollback(false)
public void crud(){
//Given
Post post = new Post();
post.setTitle("Hello Spring Boot Common");
assertThat(post.getId()).isNull(); // Transient 상태
//When
Post newPost = postRepository.save(post);
//Then
assertThat(newPost.getId()).isNotNull();
}
}
Hibernate:
call next value for hibernate_sequence
PagingAndSortingRepository 의 기능
- Iterable<T> findAll(Sort sort)
- Page<T> findAll(Pageable pageable)
- 오버 로딩이 되어있으나, 주로 Pageable 을 사용하게 된다.
- PostgresQL 기준으로 limit 를 사용하여 페이징을 위한 쿼리를 만든다.
@RunWith(SpringRunner.class)
@DataJpaTest
public class PostRepositoryTest {
@Autowired
private PostRepository postRepository;
@Test
@Rollback(false)
public void crud(){
//Given
Post post = new Post();
post.setTitle("Hello Spring Boot Common");
assertThat(post.getId()).isNull(); // Transient 상태
//PagingAndSortingRepository
//When
Page<Post> page = postRepository.findAll(PageRequest.of(0, 10));
//Then
assertThat(page.getTotalElements()).isEqualTo(1);
assertThat(page.getNumber()).isEqualTo(0);
assertThat(page.getSize()).isEqualTo(10);
assertThat(page.getNumberOfElements()).isEqualTo(1);
}
}
- Pageable 은 펙토리 메서드로 of 를 제공하며 (페이지, 사이즈) 의 매개값을 갖는다.
- Page<T> 는 유용한 메서드를 제공하는데, getNumber() = 페이지번호, getTotalElement() = 원소개수, getSize() = 요청한 사이즈, getNumberOfElements() = 원소의 개수 등이다. getContent() 는 List<T> 로 데이터를 반환시켜준다.
Hibernate:
select
post0_.id as id1_2_,
post0_.title as title2_2_
from
post post0_ limit ?
2020-11-15 17:44:54.104 TRACE 15240 --- [ main] o.h.type.descriptor.sql.BasicExtractor : extracted value ([id1_2_] : [BIGINT]) - [1]
제시되어있는 명령어를 입력하여 JPA 로 하여금 원하는 쿼리를 생성하게 할 수도 있다.
public interface PostRepository extends JpaRepository<Post,Long> {
// 메서드 이름을 분석하여 쿼리를 만들어주는 기능
Page<Post> findByTitleContains(String title, Pageable pageable);
Long countByTitleContains(String title);
}
@RunWith(SpringRunner.class)
@DataJpaTest
public class PostRepositoryTest {
@Autowired
private PostRepository postRepository;
@Test
@Rollback(false)
public void crud(){
//Given
Post post = new Post();
post.setTitle("Hello Spring Boot Common");
assertThat(post.getId()).isNull(); // Transient 상태
//When
page = postRepository.findByTitleContains("Spring", PageRequest.of(0, 10));
//Then
assertThat(page.getTotalElements()).isEqualTo(1);
assertThat(page.getNumber()).isEqualTo(0);
assertThat(page.getSize()).isEqualTo(10);
assertThat(page.getNumberOfElements()).isEqualTo(1);
//When
Long count = postRepository.countByTitleContains("Spring");
//Then
assertThat(count).isEqualTo(1);
}
}
Like 연산자 / count 함수를 사용한 모습
Hibernate:
select
post0_.id as id1_2_,
post0_.title as title2_2_
from
post post0_
where
post0_.title like ? escape ? limit ?
2020-11-15 17:44:54.172 TRACE 15240 --- [ main] o.h.type.descriptor.sql.BasicBinder : binding parameter [1] as [VARCHAR] - [%Spring%]
2020-11-15 17:44:54.173 TRACE 15240 --- [ main] o.h.type.descriptor.sql.BasicBinder : binding parameter [2] as [CHAR] - [\]
2020-11-15 17:44:54.174 TRACE 15240 --- [ main] o.h.type.descriptor.sql.BasicExtractor : extracted value ([id1_2_] : [BIGINT]) - [1]
Hibernate:
select
count(post0_.id) as col_0_0_
from
post post0_
where
post0_.title like ? escape ?
2020-11-15 17:44:54.199 TRACE 15240 --- [ main] o.h.type.descriptor.sql.BasicBinder : binding parameter [1] as [VARCHAR] - [%Spring%]
2020-11-15 17:44:54.208 TRACE 15240 --- [ main] o.h.type.descriptor.sql.BasicBinder : binding parameter [2] as [CHAR] - [\]
2020-11-15 17:44:54.277 TRACE 15240 --- [ main] o.h.type.descriptor.sql.BasicExtractor : extracted value ([col_0_0_] : [BIGINT]) - [1]
'springframework > Spring Data JPA' 카테고리의 다른 글
Spring Data Common : Null 처리 (0) | 2020.11.15 |
---|---|
Spring Data Common : Repository 인터페이스 정의 (0) | 2020.11.15 |
Spring Data JPA 활용 개요. (0) | 2020.11.15 |
JPA 생성 쿼리 파라미터 로깅, Spring Data JPA 사용시 명심해야 할 것들 (0) | 2020.11.14 |
Spring Data JPA 의 원리와 소개 (0) | 2020.11.14 |