본문 바로가기
책벌레와 벌레 그 사이 어딘가/개념쌓기

[개념쌓기] - JPA : @Query

by veganwithbacon 2022. 8. 22.
반응형

인스타그램 클론코딩을 하기로 팀원들하고 정했다.기간도 짧고 구현해보고 싶은 것도 많다보니 역할을 나눠서 하기로 했다. 좋아요를 눌러서 카운트 하는 기능을 담당하게 되었는데, 좋아요를 게시물마다 유저가 한번만 누를 수 있게 하고, 해당 유저가 해당 게시물에 다시 한번 좋아요를 누르게될 경우 좋아요를 취소하는 방식을 고민하다가 @Query를 접하게 되어서 이번 기회에 확실하게 공부하기로 했다.

 

uplikeCount를 호출시 Articles를 a로 부르기로 했으니, a에 있는 likeCount에 a.likeCount+1의 값을 대입해주는 것이고 뒤에 where절은 어디서? a.articlesId에 id라는 변수를 넣어주는 것이다.

= :id에서 ':'가 변수를 받아 쿼리를 작성시 사용

이 코드는 Repository에 있는 코드인데 JPA로 개발시에는 Repository에서 키워드만 잘 조합하면 모든 쿼리를 자동으로 만들어줘서 편리하다. 그러나 조금만 복잡해져도 쿼리 메소드가 매우 길어진다.그래서 나온 @Query 쿼리 어노테이션을 이용해 자세한 조건을 줄 수 있다.

 

 

@Query어노테이션은 @NamedQuery 또는 orm.xml에 정의한 named queries보다 우선순위가 높다

또한 @Query는 domain model이 아닌 Repository안에 있는 메소드에 위치시킬 것을 권장한다.

 

  메소드 이름 vs. @Query 쿼리 생성 비교 

메소드 이름으로 쿼리 생성

public interface MemberRepository extends JpaRepository<Member, Long> {
	List<Member> findByUsernameAndAgeGreaterThan(String username, int age);
}

메소드 이름으로 쿼리 생성할 경우 파라미터가 늘어날 수록 너무 길어진다는 단점을 지닌다

 

@Query 어노테이션을 이용한 쿼리 직접 정의

public interface MemberRepository extends JpaRepository<Member, Long> {
	@Query("select m from Member m where m.username = :username and m.age = :age")
	List<Member> findUser(@Param("username") String username, @Param("age") int age);
}

실행할 메소드에 정적 쿼리를 직접 작성하여 이름없는 Named 쿼리라 할 수 있다.

 

  Query 메소드에 파라미터 넘기기

쿼리에 두가지 방식으로 파라미터를 넘길 수 있다.

첫번째는 파라미터의 index(순서),두번째는 파라미터 이름 기반이다.

 

 

Indexed Query Parameter

JPQL

@Query("SELECT u FROM User u WHERE u.status = ?1")
User findUserByStatus(Integer status);

@Query("SELECT u FROM User u WHERE u.status = ?1 and u.name = ?2")
User findUserByStatusAndName(Integer status, String name);

위 코드처럼 쿼리문에 ?1, ?2로 순서를 정하고 메소드 파라미터에 순서에 맞게 파라미터를 넣어주면 된다.

 

Native

@Query(
  value = "SELECT * FROM Users u WHERE u.status = ?1", 
  nativeQuery = true)
User findUserByStatusNative(Integer status);

Native SQL도 JPQL과 동일하다.

 

Named Parameters

위 Indexed QUERY보다 Named Paramters를 사용하는 것을 권장하며, 순서로 지정시 헷갈릴 수 있으나

Named Parameter는 @Param어노테이션을 통해 파라미터를 매칭해주기 때문이다.

 

JPQL

@Query("SELECT u FROM User u WHERE u.status = :status and u.name = :name")
User findUserByStatusAndNameNamedParams(
  @Param("status") Integer status, 
  @Param("name") String name);

쿼리문 내 :abc로 위치를 알려주고 @Param("abc") String abc로 파라미터를 넘겨준다

 

@Query(value = "SELECT * FROM Users u WHERE u.status = :status and u.name = :name", 
  nativeQuery = true)
User findUserByStatusAndNameNamedParamsNative(
  @Param("status") Integer status, @Param("name") String name);

native SQL도 JPQL과 동일하다

 

 

  Collection Parameter

파라미터로 Collection 객체를 넘길 수도 있다

@Query(value = "SELECT u FROM User u WHERE u.name IN :names")
List<User> findUserByNameList(@Param("names") Collection<String> names);

 

  @Modifiying

@Query 어노테이션 메소드를 이용해 INSERT, UPDATE, DELETE등 DB에 변화가 발생하는 작업을 하기 위해서는 @Modifying 어노테이션을 필수로 붙여야한다

 

JPQL

 

Native

@Transactional
@Modifying
@Query(value= " update Articles a set a.likeCount=?+1 where a.articlesId = ?",nativeQuery = true)
int downlikeCount(Long id);

참고자료:

https://velog.io/@totw5701/JPA-Query-%EC%96%B4%EB%85%B8%ED%85%8C%EC%9D%B4%EC%85%98

Spring Data JPA @Query

 

Spring Data JPA @Query | Baeldung

Learn how to use the @Query annotation in Spring Data JPA to define custom queries using JPQL and native SQL.

www.baeldung.com

https://ppomelo.tistory.com/156

https://jy-note.tistory.com/12

https://yoonbing9.tistory.com/32

https://wonit.tistory.com/470

반응형

댓글