인스타그램 클론코딩을 하기로 팀원들하고 정했다.기간도 짧고 구현해보고 싶은 것도 많다보니 역할을 나눠서 하기로 했다. 좋아요를 눌러서 카운트 하는 기능을 담당하게 되었는데, 좋아요를 게시물마다 유저가 한번만 누를 수 있게 하고, 해당 유저가 해당 게시물에 다시 한번 좋아요를 누르게될 경우 좋아요를 취소하는 방식을 고민하다가 @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
https://ppomelo.tistory.com/156
https://jy-note.tistory.com/12
'책벌레와 벌레 그 사이 어딘가 > 개념쌓기' 카테고리의 다른 글
[개념쌓기]NginX? + 설치까지 (0) | 2022.08.23 |
---|---|
[개념쌓기]@Builder (0) | 2022.08.23 |
[개념쌓기] CORS-크로스 도메인_프로토콜 문제 (0) | 2022.08.19 |
[개념쌓기]CASCADE?OrphanRemoval? (0) | 2022.08.18 |
[개념쌓기] CORS (0) | 2022.08.15 |
댓글