[JPA] 자주 사용하는 메소드 사용방법 CRUD

728x90

JPA에서 자주 사용하는 메소드를 정리 해보도록 하겠습니다.

메소드 정리 및 예시 또한 적어보겠습니다.

 

CRUD

1) findAll()
  • 위 메소드는 DB 데이터를 조회(select)할 때 사용이 됩니다
	@Test
	void SelectTest2() {
		List<Question> allList = this.questionRepository.findAll();
		assertEquals(2, allList.size());

		Question q = allList.get(0);
		assertEquals("안녕?",q.getSubject());
	}

우리는 총 2건의 데이터를 insert했기 때문에 데이터의 사이즈는 2가 되어야 합니다.

데이터 사이즈가 2인지 확인하기 위해 JUnit의 assertEquals 메서드를 사용했습니다.

assertEquals는 assertEquals(기대값, 실제값)와 같이 사용하고 기대값과 실제값이 동일한지를 확인합니다.

만약 기대값과 실제값이 동일하지 않다면 테스트는 실패로 처리되고, 우리가 저장한 첫번째 데이터의 제목이 "안녕?"

이랑 일치하는지도 테스트했습니다.

 

2) findById()
	@Test
	void findByIdTest() {
		Optional<Question> oq = this.questionRepository.findById(1);
		if(oq.isPresent()) {
			Question q = oq.get();
			assertEquals("안녕?",q.getSubject());
		}
	}
  • id값에 따른 데이터 조회하기 (id값 => primary key) 입니다.

id 값으로 데이터를 조회하기 위해서는 리포지터리의 findById 메서드를 사용해야 한다.

하지만 findById의 리턴 타입은 Question이 아닌 Optional임을 알아야 합니다.

Optional은 null 처리를 유연하게 처리하기 위해 사용하는 클래스로  isPresent()메서드로

null이 아닌지를 체크하고 get으로 실제 Question 객체 값을 얻어 옵니다.

 

3) save() 
  • 위 메소드는 DB에 데이터를 삽입(insert) 할 때 사용이 됩니다. 
	@Test
	void testJpa() {
		Question q1 = new Question();
		q1.setSubject("안녕?");
		q1.setContent("안녕하세요 해야지");
		q1.setWirteday(Timestamp.from(Instant.now()));
		this.questionRepository.save(q1);

		Question q2 = new Question();
		q2.setSubject("뭐하냐?");
		q2.setContent("지금 뭐하냐고");
		q2.setWirteday(Timestamp.from(Instant.now()));
		this.questionRepository.save(q2);
	}

 

간단하게 테스트 코드를 작성하여 해봤습니다. 위 코드를 실행하면은 제 DB에 데이터가 insert된 것을 확인할 수 있습니다.

 

 

4) save() ->  Update하기

 

	@Test
	void Update() {
		Optional<Question> oq = this.questionRepository.findById(5);
		assertTrue(oq.isPresent());
		Question q = oq.get();
		q.setSubject("수정된 제목");
		this.questionRepository.save(q);
	}
assertTrue(값) 은 값이 true인지를 테스트 한다.

 

질문 데이터를 조회한 다음 subject를 "수정된 제목" 이라는 값으로 수정했다.

변경된 Question 데이터를 저장하기 위해서는 this.questionRepository.save(q) 처럼

레포지터리의 insert했던 save 메서드를 사용한다

테스트 수행 시 콘솔 창에 update 문이 실행되었음을 확인 할 수 있다.

 

5) delete() 
	@Test
	void deleteTest() {
		assertEquals(2, this.questionRepository.count());
		Optional<Question> oq = this.questionRepository.findById(5);
		assertTrue(oq.isPresent());
		Question q = oq.get();
		this.questionRepository.delete(q);
		assertEquals(5, this.questionRepository.count());
	}

Question 리포지터리의 delete 메서드를 사용하여 데이터를 삭제했습니다.

삭제하기 전에는 데이터 건수가 2, 삭제한 후에는 데이터 건수가 1인지를 테스트했습니다.

 


직접 만들어서 핸들링 하기

우리가 직접 JPA메소드를 만들어서 핸들링 하는 방법 또한 있습니다.

 

#게시판에서 제목을 통한 글 조회하기

레포지토리

public interface QuestionRepository extends JpaRepository<Question,Integer> {
	Question findBySubject(String subject);
}

실행

	@Test
	void findBySubjectTest() {
		Question q = this.questionRepository.findBySubject("안녕?");
		assertEquals("5", q.getId());
	}

 

위 과정을 하면은 Subejct으로 테이블 데이터를 조회할 수 있습니다.

생각을 해보면 인터페이스를 선언하기는 했는데 Mybatis 처럼 직접 구현을 하지 않았는데 어떻게 실행이 될까 하는

의문이 생겨야 합니다.

 

이러한 의문은 JpaRepository를 상속한 QuestionRepository 객체가 생성될때 벌어집니다.

(DI에 의해 스프링이 자동으로 QuestionRepository 객체를 생성한다. 이 때 프록시 패턴이 사용된다고 한다.)

리포지터리 객체의 메서드가 실행될때 JPA가 해당 메서드명을 분석하여 쿼리를 만들고 실행한다.

즉,  findBy + 엔티티의 속성명(예:findBySubject)과 같은 리포지터리 메서드를 작성하면 해당 속성의 값으로 데이터를 조회할수 있습니다.

 

#제목과내용을 함께 조회하기

레포지토리

public interface QuestionRepository extends JpaRepository<Question,Integer> {
	Question findBySubjectAndContent(String subject, String content);
}

요번에는 파라미터 타입이 2개이다, 즉 2개의 값을 넘겨줘야 한다.

    @Autowired
    private QuestionRepository questionRepository;

    @Test
    void testJpa() {
        Question q = this.questionRepository.findBySubjectAndContent(
                "안녕?", "안녕하세요 해야지");
        assertEquals(5, q.getId());
    }

 

실제로 이 쿼리가 조회되는 로그를 보면은 

테스트 실행 후 콘솔 창에

select
    question0_.id as id1_5_,
    question0_.content as content2_5_,
    question0_.create_date as create_d3_5_,
    question0_.subject as subject4_5_ 
from
    question question0_ 
where
    question0_.subject=? 
    and question0_.content=?

이런 로그가 뜰 것이다. 이 로그는 우리가 yml(properties)에 JPA 설정을 해줬기 때문에 뜬다. (안하면 안뜸..)

 

#특정 문자열이 포함된 데이터 조회

레포지토리

public interface QuestionRepository extends JpaRepository<Question,Integer> {
	List<Question> findBySubjectLike(String subject);
}

 

테스트코드

	@Test
	void likeTest() {
		List<Question> qList = this.questionRepository.findBySubjectLike("안녕%");
		Question q = qList.get(0);
		assertEquals("안녕?", q.getSubject());
	}
  1. 안녕%       -> '안녕' 으로 시작 하는 문자열
  2. %안녕       -> '안녕' 으로 끝나는 문자열
  3. %안녕%    -> '안녕' 을 포함하는 문자열

like 쿼리를 사용한다고 하면은 이 정도는 기본적으로 알고 사용하면 좋습니다.

 

 

위 메소드 말고도 여러가지가 있다.

항목 예제 설명
And findBySubjectAndContent(String subject, String content) 여러 컬럼을 and 로 조회
Or findBySubjectOrContent(String subject, String content) 여러 컬럼을 or 로 조회
Between findByCreateDateBetween(LocalDateTime fromDate, LocalDateTime toDate) 컬럼을 between으로 조회
LessThan findByIdLessThan(Integer id) 보다 작은 항목 검색
GreaterThanEqual findByIdGraterThanEqual(Integer id) 크거나 같은 항목 검색
Like findBySubjectLike(String subject) like 검색
In findBySubjectIn(String[] subjects) 여러 값중 하나 항목 검색
OrderBy findBySubjectOrderByCreateDateAsc(String subject) 검색 결과 정렬하여 전달

 

여기 메소드를 사용할 때 return 값을 설정할 떄도 중요하다 검색결과가 하나일 때는String

검색결과가 원하는 데이터 1줄(num=1에 해당하는 데이터) 일때는 Quesion(=클래스이름)

검색결과가 여러 건 일경우는 List<Quesion> 이런식으로 담아야 한다.

 

백엔드 개발자라면은 DB에 담고, DB 데이터를 얼마나 잘 꺼내서 사용하는직 중요하다고 생각함으로 이 부분은 

기본적으로 생각을 하고서 코드를 짜야한다고 생각합니다.

 

자세한건 공식문서를 보면 참조할 수 있습니다.

 

공부를 하면서 내용을 좀 더 추가하도록 하겠습니다. 감사합니다.

 

 

ref : https://wikidocs.net/160890

728x90