Skip to content

Commit f8b2420

Browse files
committed
refactor : project list api에 발생하던 N+1 해결을 위해 user수정
1 parent 8648393 commit f8b2420

File tree

19 files changed

+336
-233
lines changed

19 files changed

+336
-233
lines changed

src/main/java/NextLevel/demo/img/ImgDto.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,10 @@
33
import NextLevel.demo.img.entity.ImgEntity;
44
import lombok.Getter;
55
import lombok.Setter;
6+
import lombok.ToString;
67

78
@Getter @Setter
9+
@ToString
810
public class ImgDto {
911

1012
private static final String DEFAULT_IMG_URI = "very_very_long_and_long_default_img.png";

src/main/java/NextLevel/demo/project/project/dto/response/ResponseProjectDetailDto.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ public static ResponseProjectDetailDto of(ProjectEntity entity, Long fundingPric
5353
dto.setSum(fundingPrice);
5454
dto.setCompletionRate(FundingUtil.getCompletionRate(dto.sum, dto.goal));
5555
dto.setLikeCount(entity.getLikes().size());
56-
dto.setIsAuthor(entity.getUser().getId() == userId);
56+
dto.setIsAuthor(entity.getUser().getId().equals(userId));
5757
dto.status = entity.getProjectStatus().name();
5858
dto.startAt = entity.getStartAt();
5959
dto.expiredAt = entity.getExpiredAt();

src/main/java/NextLevel/demo/project/project/dto/response/ResponseProjectListDetailDto.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
import lombok.NoArgsConstructor;
2020
import lombok.Setter;
2121
import lombok.ToString;
22+
import org.hibernate.Hibernate;
2223

2324
@Getter
2425
@Setter

src/main/java/NextLevel/demo/project/project/dto/response/ResponseProjectListDto.java

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package NextLevel.demo.project.project.dto.response;
22

33
import java.util.ArrayList;
4+
import java.util.Arrays;
45
import java.util.List;
56
import lombok.Getter;
67
import lombok.NoArgsConstructor;
@@ -19,4 +20,14 @@ public ResponseProjectListDto(List<ResponseProjectListDetailDto> projects, long
1920
this.page = page;
2021
this.totalCount = totalCount;
2122
}
23+
24+
@Override
25+
public String toString() {
26+
return "ResponseProjectListDto{" +
27+
"projects=" + Arrays.toString(projects.toArray()) +
28+
", totalCount=" + totalCount +
29+
", pageCount=" + pageCount +
30+
", page=" + page +
31+
'}';
32+
}
2233
}

src/main/java/NextLevel/demo/project/project/entity/ProjectEntity.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ public class ProjectEntity extends BasedEntity {
4343
@Column(nullable = false)
4444
private String content;
4545

46-
@ManyToOne(targetEntity = ImgEntity.class, fetch = FetchType.EAGER)
46+
@ManyToOne(targetEntity = ImgEntity.class, fetch = FetchType.LAZY) // project list api에서 N+1을 발생 시킴
4747
@JoinColumn(name = "img_id")
4848
private ImgEntity titleImg;
4949

@@ -112,12 +112,12 @@ public ProjectEntity(Long id, UserEntity user, String title, String content,
112112
public String toString() {
113113
return "ProjectEntity{" +
114114
"id=" + id +
115-
", user=" + user +
115+
// ", user=" + user +
116116
", title='" + title + '\'' +
117117
", content='" + content + '\'' +
118-
", titleImg=" + titleImg +
118+
// ", titleImg=" + titleImg +
119119
", tags=" + tags +
120-
", imgs=" + stories +
120+
// ", imgs=" + stories +
121121
'}';
122122
}
123123
}

src/main/java/NextLevel/demo/project/project/repository/ProjectDslRepository.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ public ResponseProjectListDto selectProjectDsl(RequestMainPageProjectListDto dto
2727
QProjectTagEntity projectTagEntity = new QProjectTagEntity("projectTagEntity");
2828
SelectProjectListDslRepository.Builder builder = selectProjectRepository
2929
.builder(dto.getUserId())
30-
.leftJoin(projectTagEntity, QProjectEntity.class, (project)->projectTagEntity.project.id.eq(project.id), false);
30+
.leftJoin(projectTagEntity, QProjectEntity.class, (project)->projectTagEntity.project.id.eq(project.id));
3131

3232
String search = dto.getSearch();
3333
if(search != null && !search.isEmpty())

src/main/java/NextLevel/demo/project/select/SelectProjectListDslRepository.java

Lines changed: 4 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ public Builder(JPAQueryFactory queryFactory, Long userId) {
5858
.select(projectEntity.count())
5959
.from(projectEntity)
6060
.leftJoin(likeEntity).on(likeEntity.project.id.eq(projectEntity.id))
61-
.leftJoin(isLikeEntity).on(likeEntity.project.id.eq(projectEntity.id).and(isLikeEntity.user.id.eq(userId)))
61+
.leftJoin(isLikeEntity).on(likeEntity.project.id.eq(projectEntity.id).and(userId!=null?isLikeEntity.user.id.eq(userId):Expressions.FALSE))
6262
.leftJoin(viewEntity).on(viewEntity.project.id.eq(projectEntity.id));
6363

6464
mainQuery = queryFactory
@@ -79,23 +79,16 @@ public Builder(JPAQueryFactory queryFactory, Long userId) {
7979
.leftJoin(projectEntity.user, userEntity).fetchJoin()
8080
.leftJoin(projectEntity.titleImg).fetchJoin()
8181
.leftJoin(likeEntity).on(likeEntity.project.id.eq(projectEntity.id))
82-
.leftJoin(isLikeEntity).on(likeEntity.project.id.eq(projectEntity.id).and(isLikeEntity.user.id.eq(userId)))
82+
.leftJoin(isLikeEntity).on(likeEntity.project.id.eq(projectEntity.id).and(userId!=null?isLikeEntity.user.id.eq(userId):Expressions.FALSE))
8383
.leftJoin(viewEntity).on(viewEntity.project.id.eq(projectEntity.id));
8484
}
8585
public <T extends EntityPathBase,J extends EntityPathBase> Builder leftJoin(
8686
T joinEntity,
87-
Class<J> entityClass, FunctionInterface<BooleanExpression, J> onFunction,
88-
boolean isFetch
87+
Class<J> entityClass, FunctionInterface<BooleanExpression, J> onFunction
8988
){
9089
J entity = (J) getEntity(entityClass);
91-
if(isFetch) {
92-
log.info("fetch join" + joinEntity.toString());
93-
//mainQuery.leftJoin(joinEntity).on(onFunction.function(entity)).fetchJoin();
94-
//mainQuery.join(projectEntity.options).fetchJoin();
95-
}
96-
else
97-
mainQuery.leftJoin(joinEntity).on(onFunction.function(entity));
9890

91+
mainQuery.leftJoin(joinEntity).on(onFunction.function(entity));
9992
totalCountQuery.leftJoin(joinEntity).on(onFunction.function(entity));
10093
return this;
10194
}

src/main/java/NextLevel/demo/project/select/refactoring.txt

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -127,4 +127,9 @@ query dsl을 도입하고자 하는 사람들에게
127127
진짜 다 쓸모 없고 조건에 맞는 List<Long> pk값 조회하고 다른 정보들 싹다 sub query 때는게 더 빠름 결론이 진심 ㅈ같다
128128

129129
결론 : project list api는 최대한 left join으로 최적화에 성공했음 때문에 일단 funding 정보는 따로 조회하는 걸로 이번 refactoring을 마무리한다
130-
추후 현 query 조회 속도를 측정하고 main query와 list query를 분리한다
130+
추후 현 query 조회 속도를 측정하고 main query와 list query를 분리한다
131+
132+
추가 수정 left join fetch는 QEntity만으로 부족하다
133+
join(projectEntity.projectTag, tagEntity).fetchJoin() 방식이 필요하다
134+
문명 QProjectEntity의 연결된 변수들 중 QProjectTagEntity.class와 같은 변수를 찾는다면 찾을 수는 있다
135+
하지만 left join중에 더 이상 fetch가 필요한 table이 없음으로 fetch = false 로 고정한다

src/main/java/NextLevel/demo/user/dto/user/response/UserSummeryInfoDto.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,12 @@
44
import lombok.Getter;
55
import lombok.NoArgsConstructor;
66
import lombok.Setter;
7+
import lombok.ToString;
78

89
@NoArgsConstructor
910
@Getter
1011
@Setter
12+
@ToString
1113
public class UserSummeryInfoDto {
1214

1315
private String name;

src/main/java/NextLevel/demo/user/entity/UserDetailEntity.java

Lines changed: 6 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,6 @@
11
package NextLevel.demo.user.entity;
22

3-
import jakarta.persistence.CascadeType;
4-
import jakarta.persistence.Column;
5-
import jakarta.persistence.Entity;
6-
import jakarta.persistence.FetchType;
7-
import jakarta.persistence.Id;
8-
import jakarta.persistence.JoinColumn;
9-
import jakarta.persistence.MapsId;
10-
import jakarta.persistence.OneToOne;
11-
import jakarta.persistence.Table;
3+
import jakarta.persistence.*;
124
import lombok.*;
135
import org.hibernate.annotations.ColumnDefault;
146

@@ -18,12 +10,11 @@
1810
@NoArgsConstructor(access = AccessLevel.PROTECTED)
1911
public class UserDetailEntity {
2012
@Id
21-
@Column(name = "user_id")
22-
private Long userId;
13+
@GeneratedValue(strategy = GenerationType.IDENTITY)
14+
private Long id;
2315

24-
@MapsId
25-
@OneToOne(targetEntity = UserEntity.class, fetch = FetchType.LAZY, cascade = {CascadeType.PERSIST, CascadeType.REMOVE})
26-
@JoinColumn(name="user_id")
16+
@ManyToOne(targetEntity = UserEntity.class, fetch = FetchType.LAZY, cascade = {CascadeType.PERSIST, CascadeType.REMOVE})
17+
@JoinColumn(name="user_id", unique = true)
2718
private UserEntity user;
2819

2920
@Column(length = 36, columnDefinition = "CHAR(36)", unique = true, nullable = false) // default 값 없음 무조건 코드로 넣기 필수 !!
@@ -60,4 +51,5 @@ public UserDetailEntity(UserEntity user, String UUID, String role, String email)
6051
}
6152

6253
public void setEmail(String email) {this.email = email;}
54+
public Long getUserId() { return user.getId(); }
6355
}

0 commit comments

Comments
 (0)