velog와 비슷한 느낌의 news-feed 프로젝트의 마지막날 추가 기능 구현을 위해 미리 entity상 jpa로 연결해둔 테이블을 드디어 join해서 조회할 로직이 필요한 순간이 왔다
이런 추가 기능이였는데 우리는 더 나아가 팔로우 기능을 넣어 팔로우한 유저의 게시글 혹은 좋아요 누른 게시글 목록을 불러와야 했다
board-user-follow, board-user-like 이렇게 이미 연결 지어준 테이블을 join해서 service로 넘겨주는 작업을 진행했다.
똑똑한 우리 팀장님이 이미 entity끼리 연결 관계를 fetch join으로 해뒀기 때문에 악명높은 N+1은 마주하지 못했다
일부러 fetch지우고 빈틈을 만들어서 에러를 발생시키고 싶었으나 강제로 에러 만드는것도 어렵더군,,
// board
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long boardId;
@Column(nullable = false)
private String boardTitle;
@Column(nullable = false)
private String boardContent;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "user_id", nullable = false)
private User user;
@OneToMany(mappedBy = "board", cascade = CascadeType.REMOVE, orphanRemoval = true)
private List<Comment> comments;
}
// user
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long userId;
@Column(nullable = false)
private String userName;
@Column(nullable = false)
private String userPassword;
@Column(nullable = false)
private String userEmail;
@Column(nullable = false)
private String userImageUrl;
@Column(nullable = false)
private String userIntroduce;
@Column(nullable = false)
@Enumerated(EnumType.STRING)
private UserRole userRole;
일차적으로 JPA 쿼리문을 짜기 전에 MySql 워크벤치에서 join했을때 잘 나오는지 부터 만들어봤는데
select b.board_title, b.board_content from board as b
join `user` u
on b.user_id = u.user_id
where u.user_id in (
select follower_id from `follow` f
where following_id = 1
);
팔로우 하고 있는 유저의 아이디를 in절로 묶어 id를 담아 해당 아이디를 가지고 있는 유저들의 게시글을 조회해 주었다.
아직 쿼리짜는 실력 녹슬지 않았군 아주 만족했다 ㅋㅋ
(팀장님이 in 쓰라고 조언해주신건 비밀)
원래는 with절을 통한 서브쿼리로 하려고 했는데 장단점도 한번 다뤄봐야겠다
이제 문제는 이걸 JPA쿼리로 작성해야 하는데 살짝? 다르다
JPA 프레임워크에서 repository파일에 직접 쿼리문을 작성하기 위해서는 @Query 어노테이션과 함께 작성한다.
찾아보니..
SQL과 유사한 JPQL (Java Persistence Query Language) 라는 객체지향 쿼리 언어를 통해 복잡한 쿼리 처리를 지원
라고 멋있게 말하고 있다..
코드 빨리 보러가자
@Query(
"select b from Board b join fetch b.user u where u in " +
"(select f.follower from Follow f where f.following.userId = :userId)"
)
List<Board> findAllUserFollowerBoard(@Param("userId") Long userId);
@Param을 통해 userId를 파라미터로 받아 :userId 와 같은 형태로 쿼리문에 동적으로 할당할 수 있다 잘 보면 미리 작성해둔 쿼리문과 다르다는 것을 알 수 있을 텐데 JPA가 객채로 가져오기 때문에 DB에 있는 테이블명 board 라던가 user, follow가 아니라 객채 Board, User, Follow로 받고 있다. 물론 인텔리제이에서 자동완성을 잘 해주기 때문에 잘 이해하고 있다면 딸깍도 가능!
이제 postman으로 테스트 해보면
좋아 쿼리문 잘 날라가고
성공~
이제 그만 알아보자
일 줄 알겠지만 다음 포스트에서 다룰 내용이 있다
다음 포스트로 ->
https://velog.io/@foqlzm12345/JPA-Reason-Count-query-validation-failed