Spring Data JPA #4 단순 게시글 처리 #1 쿼리 메서드 사용

2021. 10. 6. 14:52JAVA/Spring

본 글은 스타트 스프링 부트 도서의 내용을 복습하기 위해 작성된 글입니다.

개요

Spring Data JPA의 CrudRepository만을 이용해서 create, read, update, delete 작업이 가능하나, 이는 너무 단순 작업입니다. 실제로 더 다양한 기능을 마음대로 사용하기 위해서 추가적인 학습이 필요합니다. #4 단순 게시글 처리에서는 아래 학습을 통해서 좀더 상세한 쿼리를 호출할 수 있도록 합니다.

  • 쿼리 메소드라는 메소드의 이름만으로 원하는 SQL을 실행하는 방법 (현재)
  • @Query를 이용한 좀 더 구체화된 JPQL 처리
  • 페이징과 정렬에 대한 처리
  • Querydsl을 이용한 동적 쿼리

본 글에서는 쿼리 메소드라는 메소드의 이름만으로 원하는 SQL을 실행하는 방법을 실습합니다.

 

1. 프로젝트 생성

File->New->Spring Starter Project

모듈(라이브러리) 선택

src/main/resources/application.properties 설정

spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/jpa_ex?useSSL=false
spring.datasource.username=jpa_user
spring.datasource.password=mysql_jpa_user

#스키마 생성(create)
#spring.jpa.hibernate.ddl-auto=create
spring.jpa.hibernate.ddl-auto=update
#DDL 생성시 데이터베이스 고유의 기능을 사용하는가?
spring.jpa.generate-ddl=false
#실행되는 SQL문을 보여줄 것인가?
spring.jpa.show-sql=true
#데이터베이스는 무엇을 사용하는가?
spring.jpa.database=mysql
#로그 레벨
logging.level.org.hibernate=info
#MySQL 상세 지정
spring.jpa.database-platform=org.hibernate.dialect.MySQL5InnoDBDialect

 

boot03 프로젝트는 boot02 프로젝트를 기반으로 하기 때문에 프로젝트 생성 및 DB 스키마 생성에 대해서 어려움을 겪고 있다면 아래 포스팅을 통해서 수행할 수 있습니다.

https://yonghwankim-dev.tistory.com/130?category=978062 

 

Spring Data JPA #3 Spring Data JPA를 위한 프로젝트 생성 #1

본 글은 스타트 스프링 부트 도서의 내용을 복습하기 위해 작성된 글입니다. 0. SpringBoot 프로젝트 생성 File->New->Spring Starter Project Lombok, Spring Data JPA, MySQL Driver 라이브러리 선택 1. 프로..

yonghwankim-dev.tistory.com

 

org.zerock.persistence.BoardRepository.java

package org.zerock.persistence;

import org.springframework.data.repository.CrudRepository;
import org.zerock.domain.Board;

public interface BoardRepository extends CrudRepository<Board, Long>{
	
}

 

org.zerock.Boot03ApplicationTests.java

package org.zerock;

import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.zerock.domain.Board;
import org.zerock.persistence.BoardRepository;

@SpringBootTest
class Boot03ApplicationTests {

	@Autowired
	private BoardRepository repo;
    
	@Test
	void testInsert200() {
		// 게시물 샘플 200개 생성
		for(int i=1;i<=200;i++)
		{
			Board board = new Board();
			board.setTitle("제목.. " + i);
			board.setContent("내용..." + i + " 채우기");
			board.setWriter("user0" + (i%10));
			repo.save(board);
		}
	}
}

bno 필드 값은 자동 증가 삽입이기 때문에 다를 수 있습니다.

 

2. 쿼리(Query) 메소드 이용하기

Spring Data JPA는 메소드의 이름만으로 원하는 질의(query)를 실행할 수 있는 방법을 제공합니다. 이때 쿼리라는 용어는 'select'에만 해당됩니다. 쿼리 메소드는 다음과 같은 단어들로 시작합니다.

find..By..,
read..By,
query..By,
get..By,
count..By

예를 들어 'find..By'로 쿼리 메소드를 작성한다면 'find' 뒤에는 엔티티 타입을 지정하고 'By'뒤에는 칼럼명을 이용해서 구상합니다. 예를 들어, 제목으로 검색하고자 한다면 findBoardByTitle'이 됩니다. 이는 Board 클래스의 Title 칼럼명으로 검색하고자 한다는 의미입니다.

 

쿼리 메소드 리턴타입

  • Page<T>
  • Slice<T>
  • List<T>

가장 많이 사용되는 것은 List<T>, Page<T> 타입을 이용합니다.

org.zerock.persistence.BoardRepository.java

public interface BoardRepository extends CrudRepository<Board, Long>, QuerydslPredicateExecutor<Board>{
		
	// 게시물에서 title 제목의 모든 게시물 검색
	public List<Board> findBoardByTitle(String title);	
}

org.zerock.Boot03ApplicationTests.java 중 일부

	@Test
	void testByTitle() {
		// 게시물에서 제목이 '제목.. 177'인 게시물 검색
		repo.findBoardByTitle("제목.. 177").forEach(board->System.out.println(board));		
	}
Output

Hibernate: select board0_.bno as bno1_0_, board0_.content as content2_0_, board0_.regdate as regdate3_0_, board0_.title as title4_0_, board0_.updatedate as updateda5_0_, board0_.writer as writer6_0_ from tbl_boards board0_ where board0_.title=?
Board(bno=385, title=제목.. 177, writer=user07, content=내용...177 채우기, regdate=2021-10-04 13:11:13.0, updatedate=2021-10-04 13:11:13.0)

 

Spring Data JPA의 쿼리 메소드 작성방법 참고문서

https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#jpa.query-methods

 

Spring Data JPA - Reference Documentation

Example 109. Using @Transactional at query methods @Transactional(readOnly = true) interface UserRepository extends JpaRepository { List findByLastname(String lastname); @Modifying @Transactional @Query("delete from User u where u.active = false") void del

docs.spring.io

 

2.1 findBy를 이용한 특정 칼럼 처리

findBy로 시작하는 방식 메소드 구성

public Collection<T> findBy + 속성 이름(속성 타입)
public interface BoardRepository extends CrudRepository<Board, Long>, QuerydslPredicateExecutor<Board>{
		
	// 게시물에서 title 제목의 모든 게시물 검색
	public List<Board> findBoardByTitle(String title);	
    
	// 게시물에서 writer 작성자의 모든 게시물 검색
	public Collection<Board> findByWriter(String writer);
}
	@Test
	void testByWriter() {
		// 게시물에서 작성자 이름이 'user00'인 게시물 검색
		Collection<Board> results = repo.findByWriter("user00");
		
		results.forEach(board->System.out.println(board));
	}

 

2.2 like 구문 처리

like 구문 형태

  1. 단순한 like
  2. 키워드 + '%'
  3. '%' + 키워드
  4. '%' + 키워드 + '%'

 

4가지 like 구문 형태의 쿼리 메소드 정리

형태 쿼리 메서드
단순한 like Like
키워드 + '%' StartingWith
'%' + 키워드 EndingWith
'%' + 키워드 + '%' Containing

 

org.zerock.persistence.BoardRepository 인터페이스

public interface BoardRepository extends CrudRepository<Board, Long>{
		
	// 게시물 작성자에 writer 문자열이 포함되는 모든 게시물을 검색
	// writer LIKE % ? %
	public Collection<Board> findByWriterContaining(String writer);
}

org.zerock.Boot03ApplicationTests.java 일부

	@Test
	void testByWriterContaining() {
		// 게시물에서 작성자 이름에 '05'라는 문자가 들어있는 게시물 검색
		Collection<Board> results = repo.findByWriterContaining("05");
		
		results.forEach(board->System.out.println(board));	
	}

 

2.3 and 혹은 or 조건 처리

경우에 따라 2개 이상의 속성을 이용해서 엔티티들을 검색해야 할 때가 있습니다. 이 경우를 위해 쿼리 메서드에는 'And' 'Or'을 사용합니다. 다만, 속성이 두 개 이상일 때는 파라미터 역시 지정한 속성의 수만큼 맞춰주어야 합니다.

 

org.zerock.persistence.BoardRepository

public interface BoardRepository extends CrudRepository<Board, Long>{
	
	// 게시물의 제목에 title 문자가 포함되거나 내용에 content 문자가 포함되는 모든 게시물 검색
	// title LIKE % ? % OR content LIKE % ? %
	public Collection<Board> findByTitleContainingOrContentContaining(String title, String content);
}

org.zerock.Boot03ApplicationTests.java 일부

	@Test
	void testByTitleContainingOrContentContaining() {
		// 게시물에서 제목이 '제목.. 25' 이거나 게시물 내용이 '내용...35'인 게시물 검색
		Collection<Board> results = repo.findByTitleContainingOrContentContaining("제목.. 25", "내용...35");
		
		results.forEach(board->System.out.println(board));
	}

 

2.4 부등호 처리

쿼리 메서드에는 '>'와 '<' 같은 부등호는 'GreaterThan' 'LessThan'을 이용해서 처리할 수 있습니다.

 

org.zerock.persistence.BoardRepository

public interface BoardRepository extends CrudRepository<Board, Long>{
		
	// 게시물의 제목에 title 문자가 포함되어 있고 게시물 번호가 특정 숫자 이상인 게시물 검색
	// title LIKE % ? % AND BNO > ?
	public Collection<Board> findByTitleContainingAndBnoGreaterThan(String keyword, long num);

}

org.zerock.Boot03ApplicationTests.java 일부

	@Test
	void testByTitleAndBno() {
		// 게시물에서 제목에 '5'가 포함되어 있고 게시물의 번호가 50보다 큰 게시물 검색
		Collection<Board> results = repo.findByTitleContainingAndBnoGreaterThan("5", 50);
		
		results.forEach(board->System.out.println(board));
	}

 

2.5 order by 처리

쿼리 메서드에서 가져오는 데이터의 순서를 지정하기 위해서는 'OrderBy' + 속성 + 'Asc or Desc'를 이용해서 작성할 수 있습니다.

 

org.zerock.persistence.BoardRepository

public interface BoardRepository extends CrudRepository<Board, Long>{

	// 게시물의 번호가 특정 숫자 이상인 게시물을 게시물 번호를 기준으로 내림차순으로 검색
	// bno > ? ORDER BY bno DESC
	public Collection<Board> findByBnoGreaterThanOrderByBnoDesc(Long bno);
}

org.zerock.Boot03ApplicationTests.java 일부

	@Test
	void testBnoOrderBy() {
		// 게시물의 번호가 90보다 큰 게시물들을 게시물 번호를 기준으로 내림차순으로 검색
		Collection<Board> results = repo.findByBnoGreaterThanOrderByBnoDesc(90L);
		
		results.forEach(board->System.out.println(board));
	}

 

References

스타트 스프링 부트, 구멍가게 코딩단 저