사이먼's 코딩노트

[SpringBoot] Repository로 DB 관리하기(3) 본문

Java/SpringBoot

[SpringBoot] Repository로 DB 관리하기(3)

simonpark817 2024. 5. 7. 21:39

[Repository로 DB 관리하기]

  • QuestionRepository.java 클래스를 통해 question 데이터를 관리해봤다면, 이번에는 AnswerRepository.java 클래스를 통해 answer 데이터를 저장, 조회하는 방법을 알아봅시다.

 

[answer 데이터 저장하기]

  • answer 테이블에 데이터를 새로 저장하는 방법을 Repository를 통해 수행해봅시다.
  • 데이터를 새로 추가하여 저장할 때는 추가할 메서드는 없고, findById()를 통해 답변을 작성하고 싶은 question 데이터를 찾아 answer 데이터를 저장하면 된다.
  • SbbApplicationTests.java 클래스에서 answer 관련 Repository를 사용하기 위해 @Autowired를 통해 객체를 생성해야 한다.
  • 아래와 같이 SbbApplicationTests.java 클래스에 코드를 추가하고 실행해보면 answer 데이터 저장이 성공적으로 이루어진다.
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);
  • Optional 형식으로 findById(2) 메서드를 사용하여 id가 2인 question 데이터를 oq라는 변수에 저장한다.
  • Optional을 사용했기 때문에 oq.get()과 같이 한 번 더 데이터를 가져와야 한다.
  • 새로 추가될 a라는 answer 객체 변수에 content와 createDate 값을 저장하고, 외래키인 question_id에는 findById(2) 메서드를 통해 조회한 id = 2를 저장한다.
  • 마지막엔 this.answerRepository.save(a)를 통해 answer 데이터를 저장한다.
  • 실제 클래스를 실행해보면 먼저 findById(2)를 통해 답변을 하고자하는 question 데이터를 먼저 찾고, 해당 id를 참조하여 answer 데이터를 새로 저장한다.
  • DB 쿼리로 생각했을 때 "INSERT INTO answer SET content = '네 자동으로 생성됩니다.', question_id = 2, createDate = NOW()" 와 의미가 같다.
  • 아래 사진은 실제로 DB에서 조회한 결과, answer 데이터가 새로 추가된 모습을 볼 수 있다.

question 2의 대한 답변 answer 생성

 

[answer 데이터 조회하기]

  • 이번에는 answer 테이블에 저장된 데이터들을 조회하는 방법을 Repository를 통해 수행해봅시다.
  • question 때와 마찬가지로 findById() 메서드를 사용해서 answer 데이터를 조회해봅시다.
  • 아래와 같이 SbbApplicationTests.java 클래스에 코드를 추가하고 실행해보면 원하는 id 값에 맞는 answer 데이터 조회가 성공적으로 이루어진다.
Optional<Answer> oa = this.answerRepository.findById(1);
assertTrue(oa.isPresent());
Answer a = oa.get();
assertEquals(2, a.getQuestion().getId());
  • Optional 형식으로 findById(1) 메서드를 사용하여 id가 1인 answer 데이터를 oa라는 변수에 저장한다.
  • Optional을 사용했기 때문에 oa.get()과 같이 한 번 더 데이터를 가져와야 한다.
  • 실제 클래스를 실행해보면 id값이 1인 answer 데이터를 조회하고 조회한 answer과 연결된 question의 id가 2인지도 테스트 확인을 하게된다.
  • 외래키인 question_id를 통해 question의 데이터도 확인하기 때문에 실제로는 LEFT JOIN을 통한 SELECT 쿼리가 수행된다.
  • DB 쿼리로 생각했을 때 "SELECT a1.id, a1.content, a1.createDate, q1.id, q1.content, q1.createDate, q1.subject FROM answer a1 LEFT JOIN question a1 ON q1.id = a1.question_id WHERE a1.id = 1" 와 의미가 같다.

 

[question을 통해 answer 데이터 조회하기]

  • 위의 방법과 동일하게 answer 데이터를 조회하는 데, 이번에는 answerRepository를 통해 직접 데이터를 조회하는 것이 아니라 questionRepository을 통해 answer 데이터를 조회해봅시다.
  •  아래와 같이 SbbApplicationTests.java 클래스에 코드를 추가하고 실행해보면 원하는 question id 값에 맞게 answer 데이터 조회가 성공적으로 이루어진다.
Optional<Question> oq = this.questionRepository.findById(2);
assertTrue(oq.isPresent());
Question q = oq.get();

List<Answer> answerList = q.getAnswerList();

assertEquals(1, answerList.size());
assertEquals("네 자동으로 생성됩니다.", answerList.get(0).getContent());
  • Optional 형식으로 findById(2) 메서드를 통해 id가 2인 question 데이터를 oq라는 변수에 저장한다.
  • Optional을 사용했기 때문에 oq.get()과같이 한 번 더 데이터를 가져와야 한다.
  • 그 다음, answer 데이터는 하나의 question에 여러개가 존재할 수 있기 때문에 List 형식으로 answerList를 선언하고 q.getAnswerList()를 통해 가져온다.
  • 실제 클래스를 실행해보면 id 값인 2인 question에 해당하는 answer 데이터를 조회하고 조회된 answer 데이터가 1개이고, '네 자동으로 생성됩니다.' 라는 content 값을 가졌는지 테스트 확인을 하게된다.
  • 이 때, 코드 상에서 oq.get() 작업이 끝나고 세션이 종료되기 때문에 이런 경우를 피하기 위해서는 @Transactional 어노테이션을 사용해야 한다.
  • DB 쿼리로 생각했을 때 "SELECT * FROM answer WHERE question_id = 2" 와 의미가 같다.

 

[JPA 메서드 명령어 규칙]

  • 여지껏 Repository를 활용하여 DB 관리를 진행하면서 알 수 있는 점은, 기본적으로 JpaRepository.java에서 내장 메서드로 제공하는 메서드들도 있지만, 실제로 각 리포지터리에 메서드를 새로 선언해야하는 경우도 있었다.
  • 다시 말해 Repository의 메서드 명은 데이터를 조회하는 쿼리문의 WHERE 조건을 결정하는 역할을 한다.
  • findBySubject나 findBySubjectAndContent와 같은 메서드 외에도 수많은 조합을 사용할 수 있다.
  • 아래는 조합할 수 있는 메서드를 간단하게 표로 정리하고 쿼리와 비교하면서 예시문을 작성하였다.

JPA 메서드 명령어 규칙

 

1. AND : 여러 컬럼을 AND 로 검색

  • findBySubjectAndContent(String subject, String content)
  • SELECT * FROM question WHERE subject = ? AND content = ?;

2. OR : 여러 컬럼을 OR 로 검색

  •  findBySubjectOrContent(String subject, String content)
  • SELECT * FROM question WHERE subject = ? OR content = ?;

3. Between : 컬럼을 BETWEEN 으로 검색

  • findByCreateDateBetween(LocalDateTime fromDate, LocalDateTime toDate)
  • SELECT * FROM question WHERE create_date BETWEEN ? AND ?;

4. LessThan : 비교해서 컬럼의 값보다 작은 항목 검색

  •  findByIdLessThan(Integer id)
  • SELECT * FROM question WHERE id < ?;

5. GreaterThanEqual : 비교해서 컬럼의 값보다 크거나 같은 항목 검색

  • findByIdGreaterThanEqual(Integer id)
  • SELECT * FROM question WHERE id >= ?;

6. Like : LIKE 검색

  • findBySubjectLike(String subject)
  • SELECT * FROM question WHERE subject LIKE ?;

7. In : 여러 값 중에 하나인 항목 검색

  • findBySubjectIn(String[] subjects)
  • SELECT * FROM question WHERE subject IN (?, ?, ?, ?);

8. OrderBy : 검색 결과를 정렬하여 전달

  • findBySubjectOrderByCreateDateAsc(String subject)
  • SELECT * FROM question WHERE subject = ? ORDER BY create_date ASC;
반응형