Spring-data-JPA 를 활용해 게시판 프로젝트를 진행하면서 게시글(Board)을 불러오면서 댓글의 개수를 가져오는 법에 대해 고민하다가 Formula라는 것을 접하게 되었다.
그러면서 Formula를 왜 사용했는 지 기록으로 남기면 좋을 것 같아 기록으로 남긴다.
위의 사진과 같이 게시글을 불러오는 과정에서 댓글의 개수를 보여주고 싶었고 이를 어떤식으로 처리하면 좋을 지 고민하게 됐다.
우선 게시글(Board) Entity은 이러하다
public class Board {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY) //auto_increment
private int id;
//게시글 제목
@Column(nullable = false, length = 100)
private String title;
//게시글 내용
@Lob //대용량 데이터
private String content;
//게시글 조회수
@Column(name = "viewCnt")
private int viewCount;
//작성자
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "userId")
private User user;
//댓글
@OneToMany(mappedBy = "board", fetch=FetchType.LAZY, cascade = CascadeType.ALL)
@JsonIgnoreProperties({"board"})
@OrderBy("id desc")
private List<Reply> replies;
//생성일
@CreationTimestamp
private Timestamp createDate;
}
게시글(Board)와 연관된 게시글을 모두 불러 list에 담고 해당 list의 사이즈를 반환하는 것으로 댓글 개수를 구했다.
게시글에 연관된 댓글의 정보가 아닌 댓글의 개수만 필요한 경우 List로 담게 된다면 메모리 낭비가 생기고 ResultSet을 매핑하는데까지 시간이 더 필요하기 때문에 댓글 수가 많다면 조회 시간이 길어질 것이다.
보통 SQL 문으로 쿼리를 작성한다면 아래와 같이 가능할 것이다.
Select b.*, (select count(1) from Reply where boardId = b.id)
from Board b
order by id desc
이런 식으로 쿼리를 날려가져온다면 더 효율적이지 않을까? 라는 생각과 함께 Formula를 사용하게 되었다.
@Formula 란?
JPA 의 명세는 아니지만 Hiberante에서 제공하는 @Formula
어노테이션을 사용하면 가상 컬럼을 매핑할 수 있다. 가상컬럼이라는 것은 JPA 상에는 존재하지만 DB에는 생성되지 않는 칼럼을 말한다. 주의해야 할 점은 하이버네이트 문서에도 언급되어 있지만 네이티브 SQL을 사용한다는 것이다.
가상칼럼은 @Formula
안의 정의 된 내용을 서브쿼리로 질의해 결과를 가져와 준다.
JBoss hibernate docs @Formula
이를 바탕으로 구현한 게시글(Board) Entity
public class Board {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY) //auto_increment
private int id;
//게시글 제목
@Column(nullable = false, length = 100)
private String title;
//게시글 내용
@Lob //대용량 데이터
private String content;
//게시글 조회수
@Column(name = "viewCnt")
private int viewCount;
//작성자
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "userId")
private User user;
//댓글 개수
@Formula("(SELECT count(1) FROM reply r WHERE r.boardId = id)")
private int replyCount;
@CreationTimestamp
private Timestamp createDate;
}
Formula는 기본적으로 fetchType.EAGER의 전략으로 가져온다. 하지만 게시글을 불러올 때 댓글의 개수 정보가 항상 필요로 했기에 Lazy로 수정하지 않았다
원하는 결과를 얻기 위해 쿼리문을 직접 작성해주는 방법도 있지만 @Formula
를 사용함으로 해결해 시도해보지는 않았다.