
연관 관계에 대해서
이전에 연관관계에 대해서 JPA 를 알아가며 정리 했었다
https://lifelogdevlog.inblog.io/92317
이런 연관관계를 활용하면 객체 참조만 하여 데이터를 조회할 수 있지만
N+1 조회, 쿼리가 어떻게 발생할지 모르는 상황, 로딩 방식의 차이 들이 발생한다
물론 적절히 Fetch Join 이던.. BatchSize 던..
해결할 수는 있지만, 솔직히 고된 일이다
단순하게 JPA를 사용한다면
더티체킹, 트랜잭션 관리, 객체로써의 관리 등 다양한 이점을 가져갈 수 있으니
이에 맞춰 QueryDSL 을 통해 쿼리 제어를 이용, SQL 처럼 조인을 사용하고
연관관계를 끊어 나가는 방식으로 사용하는 것이 현재 대다수의 개발 방식으로 보인다
ORM을 사용하지 않는 JOOQ 도 조만간에 포스트 해보려한다
연관관계 제거하기
유저와 유저가 올린 게시글, 게시글의 댓글 엔티티가 있을 경우
ManyToOne, OneToMany 를 사용하여 연관관계를 각각 가져 갈 수 있었다 이렇게 진행하면 FK 가 맺어지며 ORM 상 양방향으로 제어도 할 수 있었지만
복잡한 문제들이 생기게 되고 또 대용량 트래픽의 경우엔 FK 가 생기면
Insert, Update, Delete 단계에서 무조건 FK 상의 데이터가 있는지
확인하는 비용도 커지기 때문에
사실상 배제하는 것으로 알고 있고, 트랜드도 그러한 것으로 보아 엄청나게 정합성이 중요하지 않는 한 일반적으로는 FK 를 사양시키는 것이 맞는 것으로 보인다
@Entity
@Getter
@Table(name = "posts")
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class Post {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String content;
//@ManyToOne(fetch = FetchType.LAZY)
//@JoinColumn(name = "user_id")
//private User user;
private Long userId;
//@OneToMany(mappedBy = "post", fetch = FetchType.LAZY)
//private List<Comment> comments = new ArrayList<>();
// 더 이상 Comment 정보를 양방향으로 가져가지 않는다
//public Post(String content, User user) {
public Post(String content, Long userId) {
this.content = content;
this.userId = userId;
}
}
@Repository
@RequiredArgsConstructor
@Transactional
public class PostRepositoryImpl implements PostRepository {
private final JPAQueryFactory queryFactory;
@Override
public List<PostSummaryDto> findPostSummary(String username) {
return queryFactory
.select(Projections.constructor(
PostSummaryDto.class
, post.content
, comment.countDistinct().intValue()
)).from(post)
.leftJoin(post.comments, comment)
.where(post.user.username.eq(username))
.groupBy(post.id)
.fetch();
}
}
//-----------------------------------------------------------------
// 연관관계를 가져가지 않고 따로 PK를 보관해 가져가므로
@Repository
@RequiredArgsConstructor
@Transactional
public class PostRepositoryImpl implements PostRepository {
private final JPAQueryFactory queryFactory;
@Override
public List<PostSummaryDto> findPostSummary(String username) {
return queryFactory
.select(new QPostSummaryDto(
post.content
, comment.countDistinct().intValue()
)).from(post)
.leftJoin(user).on(post.userId.eq(user.id))
.leftJoin(comment).on(post.id.eq(comment.postId))
.where(user.username.eq(username))
.groupBy(post.id)
.fetch();
}
}
// SQL 처럼 쿼리를 제어 하여 Left Join 을 통해 조건을 명시하고 가져갈 수 있다Share article