리포지터리는 DB의 데이터를 처리하기 위한 인터페이스다. 엔티티는 단순히 DB와 매핑이 되는 클래스이기 때문에 실질적으로 데이터를 가져오고 처리하는 동작들은 리포지터리에서 이루어진다.
// QuestionRepository.java
public interface QuestionRepository extends JpaRepository<Question, Integer> {
}
interface QuestionRepository extends JpaRepository
QuestionRepository 인터페이스가 리포지터리가 되기 위하여 JpaRepository 인터페이스를 상속받아야 한다.
<Question, Long>
JpaRepository를 생성하기 위하여 <엔티티 타입, 해당 엔티티의 PK 속성의 타입>
을 지정해준다. 따라서 이 경우 "Question 테이블" 과 Question 테이블의 PK인 id의 타입인 "Long" 를 적어준다.
// SbbApplicationTests.java
@SpringBootTest
class SbbApplicationTests {
@Autowired // questionRepository 객체를 자동 생성
private QuestionRepository questionRepository;
@Test
void testJpa() {
Question q1 = new Question();
q1.setSubject("제목 설정");
q1.setContent("내용 설정");
q1.setCreateDate(LocalDateTime.now()); // 현재 시간 저장
this.questionRepository.save(q1); // 저장
Question q2 = new Question();
q2.setSubject("제목 설정2");
q2.setContent("내용 설정2");
q2.setCreateDate(LocalDateTime.now());
this.questionRepository.save(q2);
}
}
// findAll
List<Question> all = this.questionRepository.findAll();
assertEquals(2, all.size());
// findBy + ()
// QuestionRepository.java 에 Question findBySubject(String subject); 추가
Question q = this.questionRepository.findBySubject("sbb가 무엇인가요?");
assertEquals(1, q.getId());
Optional<Question> oq = this.questionRepository.findById(1);
assertTrue(oq.isPresent());
Question q = oq.get();
q.setSubject("수정된 제목");
this.questionRepository.save(q);
이미 저장되어 있는 값을 get으로 가져와 set으로 값을 변경하고 save를 하면 Update 쿼리가 실행된다.
( Optional : null 처리를 유연하게 처리하기 위함 )
assertEquals(2, this.questionRepository.count());
Optional<Question> oq = this.questionRepository.findById(1);
assertTrue(oq.isPresent());
Question q = oq.get();
this.questionRepository.delete(q);
assertEquals(1, this.questionRepository.count());
delete()를 통해 데이터를 삭제할 수 있다.
앞뒤에 count()를 통해 데이터 수의 변화를 확인할 수 있다.
테스트 코드에서는 DB 연결이 끊어지는 문제가 발생한다. 따라서 메서드가 종료될 때까지 DB 세션이 유지하기 위하여 @Transactional
어노테이션을 사용한다. (실제 환경에서는 DB 연결이 끊기지 않아 사용하지 않아도 된다.)
참고
점프 투 스프링부트 : https://wikidocs.net/160890