Skip to content

Commit 71e6ef2

Browse files
authored
[Merge] Merge pull request #113 from SPOTeam/refactor/112
[Refactor] 스터디 필터링 조회 성능 향상을 위한 통계성 데이터 비정규화 및 쿼리 개선
2 parents ace5b1d + b5d8d38 commit 71e6ef2

15 files changed

Lines changed: 132 additions & 212 deletions

File tree

‎modules/study/src/main/java/kr/spot/study/application/command/CreateStudyService.java‎

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,12 @@
66
import kr.spot.study.domain.associations.StudyCategory;
77
import kr.spot.study.domain.associations.StudyMember;
88
import kr.spot.study.domain.associations.StudyRegion;
9-
import kr.spot.study.domain.associations.StudyStats;
109
import kr.spot.study.domain.associations.StudyStyle;
1110
import kr.spot.study.domain.vo.Fee;
1211
import kr.spot.study.infrastructure.jpa.StudyRepository;
1312
import kr.spot.study.infrastructure.jpa.associations.StudyCategoryRepository;
1413
import kr.spot.study.infrastructure.jpa.associations.StudyMemberRepository;
1514
import kr.spot.study.infrastructure.jpa.associations.StudyRegionRepository;
16-
import kr.spot.study.infrastructure.jpa.associations.StudyStatsRepository;
1715
import kr.spot.study.infrastructure.jpa.associations.StudyStyleRepository;
1816
import kr.spot.study.presentation.command.dto.request.CreateStudyRequest;
1917
import lombok.RequiredArgsConstructor;
@@ -34,18 +32,15 @@ public class CreateStudyService {
3432
private final StudyStyleRepository studyStyleRepository;
3533
private final StudyRegionRepository studyRegionRepository;
3634
private final StudyCategoryRepository studyCategoryRepository;
37-
private final StudyStatsRepository studyStatsRepository;
3835
private final StudyMemberRepository studyMemberRepository;
3936

4037
public long createStudy(CreateStudyRequest request, long leaderId, MultipartFile imageFile) {
4138
long studyId = idGenerator.nextId();
4239
Study study = Study.of(studyId, leaderId, request.name(), request.maxMembers(),
4340
Fee.of(request.hasFee(), request.amount()), null, request.description(), request.isOnline());
44-
StudyStats studyStats = StudyStats.of(studyId);
4541
StudyMember studyMember = StudyMember.create(idGenerator.nextId(), studyId, leaderId);
4642

4743
studyRepository.save(study);
48-
studyStatsRepository.save(studyStats);
4944
studyMemberRepository.save(studyMember);
5045

5146
saveAllStudyCategories(request, studyId);

‎modules/study/src/main/java/kr/spot/study/application/command/StudyLikeService.java‎

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
package kr.spot.study.application.command;
22

33
import kr.spot.IdGenerator;
4+
import kr.spot.study.infrastructure.jpa.StudyRepository;
45
import kr.spot.study.infrastructure.jpa.associations.StudyLikeRepository;
5-
import kr.spot.study.infrastructure.jpa.associations.StudyStatsRepository;
66
import lombok.RequiredArgsConstructor;
77
import org.springframework.stereotype.Service;
88
import org.springframework.transaction.annotation.Transactional;
@@ -14,7 +14,7 @@ public class StudyLikeService {
1414

1515
private final IdGenerator idGenerator;
1616
private final StudyLikeRepository studyLikeRepository;
17-
private final StudyStatsRepository studyStatsRepository;
17+
private final StudyRepository studyRepository;
1818

1919
public void likeStudy(long studyId, long memberId) {
2020
int inserted = studyLikeRepository.saveStudyLike(idGenerator.nextId(), studyId, memberId);
@@ -23,14 +23,14 @@ public void likeStudy(long studyId, long memberId) {
2323

2424
private void increaseLikeCount(long studyId, int inserted) {
2525
if (inserted == 1) {
26-
studyStatsRepository.increaseLike(studyId);
26+
studyRepository.increaseLike(studyId);
2727
}
2828
}
2929

3030
public void unlikeStudy(long studyId, long memberId) {
3131
int deleted = studyLikeRepository.hardDelete(studyId, memberId);
3232
if (deleted > 0) {
33-
studyStatsRepository.decreaseLike(studyId);
33+
studyRepository.decreaseLike(studyId);
3434
}
3535
}
3636
}

‎modules/study/src/main/java/kr/spot/study/application/query/GetStudyDetailService.java‎

Lines changed: 4 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,11 @@
77
import kr.spot.study.domain.Study;
88
import kr.spot.study.domain.associations.StudyCategory;
99
import kr.spot.study.domain.associations.StudyMember;
10-
import kr.spot.study.domain.associations.StudyStats;
1110
import kr.spot.study.domain.enums.Category;
1211
import kr.spot.study.domain.enums.StudyMemberStatus;
1312
import kr.spot.study.infrastructure.jpa.StudyRepository;
1413
import kr.spot.study.infrastructure.jpa.associations.StudyCategoryRepository;
1514
import kr.spot.study.infrastructure.jpa.associations.StudyMemberRepository;
16-
import kr.spot.study.infrastructure.jpa.associations.StudyStatsRepository;
1715
import kr.spot.study.presentation.query.dto.response.GetStudyInfoResponse;
1816
import kr.spot.study.presentation.query.dto.response.GetStudyInfoResponse.Statistics;
1917
import kr.spot.study.presentation.query.dto.response.GetStudyMembersResponse;
@@ -32,16 +30,14 @@ public class GetStudyDetailService {
3230

3331
private final StudyRepository studyRepository;
3432
private final StudyCategoryRepository studyCategoryRepository;
35-
private final StudyStatsRepository studyStatsRepository;
3633
private final StudyMemberRepository studyMemberRepository;
3734
private final StudyViewCountService studyViewCountService;
3835
private final GetMemberInfoPort getMemberInfoPort;
3936

4037
public GetStudyInfoResponse getStudyInfo(long studyId, long viewerId) {
4138
Study study = findStudy(studyId);
42-
StudyStats stats = findStudyStats(studyId);
4339
List<Category> categories = findCategories(studyId);
44-
Statistics statistics = buildStatistics(study, stats, studyId, viewerId);
40+
Statistics statistics = buildStatistics(study, studyId, viewerId);
4541

4642
return toStudyInfoResponse(study, categories, statistics);
4743
}
@@ -58,23 +54,19 @@ private Study findStudy(long studyId) {
5854
return studyRepository.getStudyById(studyId);
5955
}
6056

61-
private StudyStats findStudyStats(long studyId) {
62-
return studyStatsRepository.getByStudyId(studyId);
63-
}
64-
6557
private List<Category> findCategories(long studyId) {
6658
return studyCategoryRepository.findAllByStudyId(studyId).stream()
6759
.map(StudyCategory::getCategory)
6860
.toList();
6961
}
7062

71-
private Statistics buildStatistics(Study study, StudyStats stats, long studyId, long viewerId) {
72-
long displayViewCount = studyViewCountService.calculateDisplayViewCount(stats, studyId,
63+
private Statistics buildStatistics(Study study, long studyId, long viewerId) {
64+
long displayViewCount = studyViewCountService.calculateDisplayViewCount(study, studyId,
7365
viewerId);
7466
return Statistics.of(
7567
study.getMaxMembers(),
7668
study.getCurrentMembers(),
77-
stats.getLikeCount(),
69+
study.getLikeCount(),
7870
displayViewCount
7971
);
8072
}

‎modules/study/src/main/java/kr/spot/study/application/query/StudyViewCountService.java‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
package kr.spot.study.application.query;
22

3-
import kr.spot.study.domain.associations.StudyStats;
3+
import kr.spot.study.domain.Study;
44
import kr.spot.view.ViewAbuseGuard;
55
import kr.spot.view.ViewCounter;
66
import kr.spot.view.ViewableType;
@@ -16,8 +16,8 @@ public class StudyViewCountService {
1616
private final ViewCounter viewCounter;
1717
private final ViewAbuseGuard viewAbuseGuard;
1818

19-
public long calculateDisplayViewCount(StudyStats stats, long studyId, long viewerId) {
20-
long baseViewCount = stats.getViewCount();
19+
public long calculateDisplayViewCount(Study study, long studyId, long viewerId) {
20+
long baseViewCount = study.getViewCount();
2121
long viewDelta = getViewDeltaFromCounter(studyId, viewerId);
2222
return baseViewCount + viewDelta;
2323
}

‎modules/study/src/main/java/kr/spot/study/domain/Study.java‎

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,10 @@ public class Study extends BaseEntity {
6060
@Column(nullable = false)
6161
private Boolean isOnline = false;
6262

63+
private Long viewCount;
64+
65+
private Long likeCount;
66+
6367
public static Study of(Long id, Long leaderId, String name, Integer maxMembers, Fee fee,
6468
String description) {
6569
return of(id, leaderId, name, maxMembers, fee, null, description, false);
@@ -75,7 +79,7 @@ public static Study of(Long id, Long leaderId, String name, Integer maxMembers,
7579
validateStudyNameIsNotBlank(name);
7680
validateMaxMembers(maxMembers);
7781
return new Study(id, leaderId, name, maxMembers, CURRENT_MEMBERS, fee, imageUrl, description,
78-
RecruitingStatus.RECRUITING, isOnline != null && isOnline);
82+
RecruitingStatus.RECRUITING, isOnline != null && isOnline, 0L, 0L);
7983
}
8084

8185
private static void validateStudyNameIsNotBlank(String name) {

‎modules/study/src/main/java/kr/spot/study/domain/associations/StudyStats.java‎

Lines changed: 0 additions & 33 deletions
This file was deleted.

‎modules/study/src/main/java/kr/spot/study/infrastructure/batch/StudyViewFlusher.java‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
package kr.spot.study.infrastructure.batch;
22

3-
import kr.spot.study.infrastructure.jpa.associations.StudyStatsRepository;
3+
import kr.spot.study.infrastructure.jpa.StudyRepository;
44
import lombok.RequiredArgsConstructor;
55
import lombok.extern.slf4j.Slf4j;
66
import org.springframework.stereotype.Component;
@@ -12,11 +12,11 @@
1212
@RequiredArgsConstructor
1313
public class StudyViewFlusher {
1414

15-
private final StudyStatsRepository studyStatsRepository;
15+
private final StudyRepository studyRepository;
1616

1717
@Transactional(propagation = Propagation.REQUIRES_NEW)
1818
public void updateViewCount(long studyId, long delta) {
19-
studyStatsRepository.increaseViewBy(studyId, delta);
19+
studyRepository.increaseViewBy(studyId, delta);
2020
log.debug("스터디 조회수 DB 업데이트: studyId={}, delta={}", studyId, delta);
2121
}
2222
}

‎modules/study/src/main/java/kr/spot/study/infrastructure/jpa/StudyRepository.java‎

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,9 @@
55
import kr.spot.study.domain.Study;
66
import kr.spot.study.domain.enums.RecruitingStatus;
77
import org.springframework.data.jpa.repository.JpaRepository;
8+
import org.springframework.data.jpa.repository.Modifying;
9+
import org.springframework.data.jpa.repository.Query;
10+
import org.springframework.data.repository.query.Param;
811

912
public interface StudyRepository extends JpaRepository<Study, Long> {
1013

@@ -16,4 +19,21 @@ default Study getStudyById(Long studyId) {
1619
long countByLeaderIdAndRecruitingStatus(long leaderId, RecruitingStatus recruitingStatus);
1720

1821
boolean existsByLeaderId(long leaderId);
22+
23+
@Modifying
24+
@Query("""
25+
update Study s
26+
set s.viewCount = s.viewCount + :delta,
27+
s.updatedAt = CURRENT_TIMESTAMP
28+
where s.id = :studyId
29+
""")
30+
int increaseViewBy(@Param("studyId") long studyId, @Param("delta") long delta);
31+
32+
@Modifying
33+
@Query("update Study s set s.likeCount = s.likeCount + 1 where s.id = :studyId")
34+
int increaseLike(@Param("studyId") long studyId);
35+
36+
@Modifying
37+
@Query("update Study s set s.likeCount = case when s.likeCount > 0 then s.likeCount - 1 else 0 end where s.id = :studyId")
38+
int decreaseLike(@Param("studyId") long studyId);
1939
}

‎modules/study/src/main/java/kr/spot/study/infrastructure/jpa/associations/StudyStatsRepository.java‎

Lines changed: 0 additions & 37 deletions
This file was deleted.

0 commit comments

Comments
 (0)