
출처 : 점프 투 스프링부트
엔티티에 의해 생성된 데이터베이스 테이블에 접근하는 메서드들(예: findAll, save 등)을 사용하기 위한 인터페이스이다.
데이터 처리를 위해서는 테이블에 어떤 값을 넣거나 값을 조회하는 등의 CRUD(Create, Read, Update, Delete)가 필요하다.
이때, 이러한 CRUD를 어떻게 처리할지 정의하는 계층이 바로 리포지터리이다.
// QuestionRepository.java(인터페이스)
package com.mysite.sbb;
import org.springframework.data.jpa.repository.JpaRepository;
public interface QuestionRepository extends JpaRepository<Question, Integer> {
}

JpaRepository<Question, Integer>
✅상속할 때는 제네릭스 타입으로 <Question, Integer> 처럼 리포지터리의 대상이 되는 엔티티의 타입(Question)과 해당 엔티티의 PK 속성 타입(Integer)을 지정해야 한다.
package com.mysite.sbb;
import org.springframework.data.jpa.repository.JpaRepository;
public interface AnswerRepository extends JpaRepository<Answer, Integer> {
}
이제 리포지터리를 이용하여 question, answer 테이블에 데이터를 저장하거나 조회할 수 있다.

이 디렉토리에서 클래스를 작성한다.
package com.mysite.sbb;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import java.time.LocalDateTime;
@SpringBootTest---①
class SbbApplicationTests {
@Autowired ---②
private QuestionRepository questionRepository;
@Test ---③
void testJpa() {
Question q1 = new Question();
q1.setSubject("sbb가 무엇인가요?");
q1.setContent("sbb에 대해서 알고 싶습니다.");
q1.setCreateDate(LocalDateTime.now());
this.questionRepository.save(q1); //첫번째 질문 저장
Question q2 = new Question();
q2.setSubject("스프링부트 모델 질문입니다.");
q2.setContent("id는 자동으로 생성되나요?");
q2.setCreateDate(LocalDateTime.now());
this.questionRepository.save(q2); //두번째 질문 저장
}
}
① - SbbApplicationTests 클래스가 스프링부트 테스트 클래스임을 의미
② - 스프링의 DI 기능으로 questionRepository 객체를 스프링이 자동으로 생성해준다.
③ - testJpa 메서드가 테스트 메서드임을 나타낸다. 위 클래스를 JUnit으로 실행하면 @Test 애너테이션이 붙은 메서드가 실행된다.
스프링이 객체를 대신 생성하여 주입한다.
객체를 주입하기 위해 사용하는 스프링의 애너테이션.
객체를 주입하는 방식에는 @Autowired외에 Setter 또는 생성자를 사용하는 방식이 있다.
순환참조 문제와 같은 이유로 @Autowired보다는 생성자를 통한 객체 주입 방식이 권장된다.
테스트코드를 작성하고 작성한 테스트코드를 실행하기 위해 사용하는 자바의 테스트 프레임워크
이다.

상단에서 테스트 클래스를 실행해보기로.. (testJpa 메서드 하나만 가지고 여러 기능을 테스트 한다.)

문제없이 테스트코드 실행이 완료되었으면, 로컬 서버를 돌려서 h2 콘솔에 접속해보기


id는 앞서 엔티티 생성 시 데이터를 생성할 때 자동으로 속성값이 1씩 증가하도록 @GeneratedValue 설정을 했다.
package com.mysite.sbb;
✅import static org.junit.jupiter.api.Assertions.assertEquals;
✅import java.util.List;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
@SpringBootTest
class SbbApplicationTests {
@Autowired
private QuestionRepository questionRepository;
@Test
void testJpa() {
List<Question> all = this.questionRepository.⭐findAll();
assertEquals(2, all.size());
Question q = all.get(0);
assertEquals("sbb가 무엇인가요?", q.getSubject());
}
}
question 테이블에 저장된 모든 데이터를 조회하기 위해 리포지터리의 findAll 메서드를 사용했다.
데이터 사이즈는 2가 되어야 한다. 2인지 확인하기 위해 JUnit 의 assertEquals 메서드를 사용했다.
assertEquals는 assertEquals(기대값, 실제값)와 같이 사용, 기대값과 실제값이 동일한지 조사한다.

만일 동일하지 않다면, 테스트는 실패로 처리한다.

id 값으로 데이터를 조회하기 위해서는 리포지터리의 findById 메서드를 사용해야 한다. findById 리턴타입은 Question이 아닌 Optional에 주의한다.
// QuestionRepository.java 클래스를 수정한다.
package com.mysite.sbb;
import org.springframework.data.jpa.repository.JpaRepository;
public interface QuestionRepository extends JpaRepository<Question, Integer> {
Question findBySubject(String subject);
}
인터페이스에 findBySubject라는 메서드를 구현만 하고, 구현은 하지 않았는데 어떻게 실행이 된거지?
🤔 즉, findBy + 엔티티의 속성명과 같은 리포지터리 메서드를 작성하면
해당 속성의 값으로 데이터를 조회할 수 있다.
// 테스트 클래스
package com.mysite.sbb;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import java.time.LocalDateTime;
import java.util.List;
import static org.junit.jupiter.api.Assertions.assertEquals;
import java.util.Optional;
@SpringBootTest
class SbbApplicationTests {
@Autowired
private QuestionRepository questionRepository;
@Test
void testJpa() {
Question q = this.questionRepository.findBySubject("sbb가 무엇인가요?");
assertEquals(1, q.getId());
}
}
application.properties

spring.jpa.properties.hibernate.format_sql=true
spring.jpa.properties.hibernate.show_sql=true
테스트 클래스를 실행시켜보면, 콘솔에 where subject가 포함된 것을 확인할 수 있다.


##findBySubjectAndContent
제목과 내용을 함께 조회해본다. 두 개의 속성을 And 조건으로 조회할 때는 리포지터리에 메서드를 추가한다.
Question findBySubjectAndContent(String subject, String content);
테스트 코드를 작성하고 실행해보자.
// testJpa() 메서드에 추가한다
Question q = this.questionRepository.findBySubjectAndContent("sbb가 무엇인가요?", "sbb에 대해서 알고 싶습니다.");
assertEquals(1, q.getId());

subject와 content가 where절에 있는 것을 확인했다.

다양하게 조합해서 사용할 수 있다고 한다. 나도 잘 활용해보고 싶어졌다.
단, 응답 결과가 여러 건인 경우에는 리포지터리의 메서드 리턴 타입을 Question이 아닌 List으로 해야 한다.
제목에 특정 문자열이 포함되어 있는 데이터를 조회한다.
package com.mysite.sbb;
import java.util.List;
import org.springframework.data.jpa.repository.JpaRepository;
public interface QuestionRepository extends JpaRepository<Question, Integer> {
Question findBySubject(String subject);
Question findBySubjectAndContent(String subject, String content);
✅List<Question> findBySubjectLike(String subject);
}

List<Question> qList = this.questionRepository.findBySubjectLike("sbb%");
Question q = qList.get(0);
assertEquals("sbb가 무엇인가요?", q.getSubject());
// sbb% : sbb로 시작하는 문자열
// %sbb : sbb로 끝나는 문자열
// %sbb% : sbb를 포함하는 문자열

package com.mysite.sbb;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;
import java.time.LocalDateTime;
import java.util.Optional;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
@SpringBootTest
class SbbApplicationTests {
@Autowired
private QuestionRepository questionRepository;
@Autowired
private AnswerRepository answerRepository;
@Test
void testJpa() {
Optional<Question> oq = this.questionRepository.findById(2);
assertTrue(oq.isPresent());
Question q = oq.get();
Answer a = new Answer();
a.setContent("네 자동으로 생성됩니다.");
a.setQuestion(q); // 어떤 질문의 답변인지 알기위해서 Question 객체가 필요하다.
a.setCreateDate(LocalDateTime.now());
this.answerRepository.save(a);
}
}

--- 이어서 작성...