[Spring JPA #10] 스프링 데이터 Common 리포지터리(Repository)
| 스프링 데이터 Common 리포지터리 예제
프로젝트 구조
├── src
│ ├── main
│ │ ├── java
│ │ │ └── com
│ │ │ └── tutorial
│ │ │ └── springbootjpa
│ │ │ ├── Post.java
│ │ │ ├── PostRepository.java
│ │ │ ├── SpringBootJpaApplication.java
│ │ └── resources
│ │ ├── application.properties
│ │ ├── static
│ │ └── templates
│ └── test
│ └── java
│ └── com
│ └── tutorial
│ └── springbootjpa
│ └── PostRepositoryTest.java
의존성 관리
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
소스 코드
@Entity
public class Comment {
@Id
@GeneratedValue
private Long id;
private String comment;
@ManyToOne
private Post post;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getComment() {
return comment;
}
public void setComment(String comment) {
this.comment = comment;
}
public Post getPost() {
return post;
}
public void setPost(Post post) {
this.post = post;
}
}
@Entity
public class Post {
@Id
@GeneratedValue
private Long id;
private String title;
@OneToMany(mappedBy = "post", cascade = CascadeType.ALL)
private Set<Comment> comments = new HashSet<>();
public void addComment(Comment comment){
this.comments.add(comment);
comment.setPost(this);
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public Set<Comment> getComments() {
return comments;
}
public void setComments(Set<Comment> comments) {
this.comments = comments;
}
@Override
public String toString() {
return "Post{" +
"id=" + id +
", title='" + title + '\'' +
'}';
}
}
public interface PostRepository extends JpaRepository<Post, Long> {
}
- JpaRepository 인터페이스는 save, findAll, findAllById ... 같은 기본적으로 Repository와 상호작용 할 수 있는 기본 메서드를 제공해줍니다.
- 프로그래머가 Repository와 인터페이스 할 수 있는 메서드를 직접 구현하는 것도 가능합니다.
테스트 코드
@RunWith(SpringRunner.class)
@DataJpaTest
public class PostRepositoryTest {
@Autowired
PostRepository postRepository;
@Test
@Rollback(false)
public void crudRepository() {
Post post = new Post();
post.setTitle("hello spring boot common");
assertThat(post.getId()).isNull();
Post newPost = postRepository.save(post);
assertThat(newPost.getId()).isNotNull();
}
}
- @Autowired 어노테이션을 통해서 위에서 작성한 PostRepository 인터페이스의 구현체인 리포지터리 빈을 주입받아 사용할 수 있습니다. 이때는 pom.xml 에서 추가한 H2 인메모리 데이터베이스를 테스트에서 Repository로 사용하게 됩니다.
- 위 테스트 코드에서 @Rollback(false)을 추가한 이유는 @DataJpaTest에서는 기본적으로 @Transational 어노테이션이 추가되어 있어 기본적으로 각 테스트들이 수행되었을 때 rollback를 하게 됩니다. 따라서 하이버네이트는 rollback될 쿼리는 수행할 필요가 없는 쿼리라 인식하여 Repository에 엔티티를 저장하는 insert문을 날리지 않게 됩니다. 따라서 원하는 테스트를 하기 위해서는 @Roallback(false)라는 어노테이션을 추가하여 rollback을 하지 않겠다는 정보를 부가해야합니다.
- 위 코드를 실행하게 되면 Post 엔티티에 원래는 할당되지 않는 id 멤버 변수에 postRepository.save(post)를 실행하게 되면서 @GeneratedValue에 의해 값이 할당되게 됩니다. 따라서 위 테스트는 통과됩니다.
다음과 같이 페이징 기능도 쉽게 구현할 수 있습니다.
@RunWith(SpringRunner.class)
@DataJpaTest
public class PostRepositoryTest {
@Autowired
PostRepository postRepository;
@Test
@Rollback(false)
public void crudRepository() {
Post post = new Post();
post.setTitle("hello spring boot common");
assertThat(post.getId()).isNull();
Post newPost = postRepository.save(post);
assertThat(newPost.getId()).isNotNull();
List<Post> posts = postRepository.findAll();
assertThat(posts.size()).isEqualTo(1);
assertThat(posts).contains(newPost);
Page<Post> page = postRepository.findAll(PageRequest.of(0, 10));
assertThat(page.getTotalElements()).isEqualTo(1);
assertThat(page.getNumber()).isEqualTo(0);
assertThat(page.getSize()).isEqualTo(10);
assertThat(page.getNumberOfElements()).isEqualTo(1);
}
}
| JpaRespository 인터페이스 메서드 추가
PostRepository 인터페이스에 다음과 같이 어떤 기능을 구현하기 위한 메서드를 추가하면 쉽게 Repository에 원하는 데이터를 찾아 올 수 있습니다. 단 여기서 Spring Data에서 요구하는 규칙을 만족해야지 제대로 된 기능이 추가됩니다.
소스 코드
public interface PostRepository extends JpaRepository<Post, Long> {
Page<Post> findByTitleContains(String title, Pageable pageable);
long countByTitleContains(String title);
}
- findBy로 시작하는 메서드는 쿼리를 요청하는 메서드를 나타내는 것입니다. 이것은 Spring Data에서 요구하는 규칙입니다. 자세한 것은 스프링 문서를 참조하면 될 것 같습니다. findByTitleContains는 Post의 title 멤버변수가 메서드의 title 인수와 같은 엔티티를 찾아 Page 형태로 리턴하는 메서드입니다.
- contBy로 시작하는 메서드는 쿼리 결과 레코드 수를 요청하는 메서드를 나타냅니다. countByTitleContains는 Post 테이블에서 해당 title에 해당하는 Post들의 개수를 찾아 반환하는 메서드입니다.
테스트 코드
@RunWith(SpringRunner.class)
@DataJpaTest
public class PostRepositoryTest {
@Autowired
PostRepository postRepository;
@Test
@Rollback(false)
public void crudRepository() {
Post post = new Post();
post.setTitle("hello spring boot common");
assertThat(post.getId()).isNull();
Post newPost = postRepository.save(post);
assertThat(newPost.getId()).isNotNull();
List<Post> posts = postRepository.findAll();
assertThat(posts.size()).isEqualTo(1);
assertThat(posts).contains(newPost);
Page<Post> page = postRepository.findAll(PageRequest.of(0, 10));
assertThat(page.getTotalElements()).isEqualTo(1);
assertThat(page.getNumber()).isEqualTo(0);
assertThat(page.getSize()).isEqualTo(10);
assertThat(page.getNumberOfElements()).isEqualTo(1);
page = postRepository.findByTitleContains("spring", PageRequest.of(0, 10));
assertThat(page.getTotalElements()).isEqualTo(1);
assertThat(page.getNumber()).isEqualTo(0);
assertThat(page.getSize()).isEqualTo(10);
assertThat(page.getNumberOfElements()).isEqualTo(1);
long spring = postRepository.countByTitleContains("spring");
assertThat(spring).isEqualTo(1);
}
}
'Spring Data > Spring Data JPA' 카테고리의 다른 글
[Spring JPA #14] 스프링 데이터 커스텀 리포지터리 만들기 (0) | 2021.03.25 |
---|---|
[Spring JPA #13] 스프링 데이터 쿼리 만들기 (0) | 2021.03.25 |
[Spring JPA #12] 스프링 데이터 Null 체크 (0) | 2021.03.25 |
[Spring JPA #11] 스프링 데이터 리포지터리 인터페이스 정의하기(Spring Repository Interface) (0) | 2021.03.25 |
[Spring JPA #9] 스프링 데이터 JPA 원리 및 스프링 데이터 구성 요소 (0) | 2021.03.25 |
[Spring JPA #8] JPA Query (0) | 2021.03.25 |
[Spring JPA #7] JPA Fetch (0) | 2021.03.25 |
[Spring JPA #6] JPA Cascade (0) | 2021.03.25 |