From d6467c8d34bbc737a418c299580b8a5c56fc78ac Mon Sep 17 00:00:00 2001 From: Ohzzi Date: Mon, 17 Oct 2022 19:37:10 +0900 Subject: [PATCH 1/3] =?UTF-8?q?feat:=20=ED=9A=8C=EC=9B=90=20=ED=8C=94?= =?UTF-8?q?=EB=A1=9C=EC=9B=8C=20=EC=88=98=EC=9D=98=20=EB=8D=B0=EC=9D=B4?= =?UTF-8?q?=ED=84=B0=20=EC=A0=95=ED=95=A9=EC=84=B1=EC=9D=84=20=EB=B0=B0?= =?UTF-8?q?=EC=B9=98=20=EC=B2=98=EB=A6=AC=ED=95=98=EB=8A=94=20=EC=BF=BC?= =?UTF-8?q?=EB=A6=AC=20=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../f12/domain/member/MemberRepository.java | 6 +++++ .../domain/member/MemberRepositoryTest.java | 23 +++++++++++++++++++ 2 files changed, 29 insertions(+) diff --git a/backend/src/main/java/com/woowacourse/f12/domain/member/MemberRepository.java b/backend/src/main/java/com/woowacourse/f12/domain/member/MemberRepository.java index 1bc2584d..0f3beb74 100644 --- a/backend/src/main/java/com/woowacourse/f12/domain/member/MemberRepository.java +++ b/backend/src/main/java/com/woowacourse/f12/domain/member/MemberRepository.java @@ -2,8 +2,14 @@ import java.util.Optional; import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Modifying; +import org.springframework.data.jpa.repository.Query; public interface MemberRepository extends JpaRepository, MemberRepositoryCustom { Optional findByGitHubId(String gitHubId); + + @Modifying(clearAutomatically = true, flushAutomatically = true) + @Query(value = "update Member m set m.followerCount = (select count(f) from Following f where f.followingId = m.id)") + void updateFollowerCountBatch(); } diff --git a/backend/src/test/java/com/woowacourse/f12/domain/member/MemberRepositoryTest.java b/backend/src/test/java/com/woowacourse/f12/domain/member/MemberRepositoryTest.java index bc07a1fa..5716c633 100644 --- a/backend/src/test/java/com/woowacourse/f12/domain/member/MemberRepositoryTest.java +++ b/backend/src/test/java/com/woowacourse/f12/domain/member/MemberRepositoryTest.java @@ -315,4 +315,27 @@ class MemberRepositoryTest { assertThatThrownBy(() -> memberRepository.save(member2)) .isInstanceOf(DataIntegrityViolationException.class); } + + @Test + void 회원의_팔로워_수의_정합성을_맞춘다() { + // given + Member member = CORINNE.생성(); + Member follower = MINCHO.생성(); + memberRepository.save(member); + memberRepository.save(follower); + Following following = Following.builder() + .followerId(follower.getId()) + .followingId(member.getId()) + .build(); + followingRepository.save(following); + + // when + memberRepository.updateFollowerCountBatch(); + + // then + Member actual = memberRepository.findById(member.getId()) + .orElseThrow(); + + assertThat(actual.getFollowerCount()).isOne(); + } } From 5f8d3a3c44f8dd6f5806c4a435140490b6797e23 Mon Sep 17 00:00:00 2001 From: Ohzzi Date: Mon, 17 Oct 2022 19:46:02 +0900 Subject: [PATCH 2/3] =?UTF-8?q?refactor:=20=EC=84=9C=EB=B9=84=EC=8A=A4=20?= =?UTF-8?q?=EB=A0=88=EC=9D=B4=EC=96=B4=EC=97=90=EC=84=9C=20=EB=AA=85?= =?UTF-8?q?=EC=8B=9C=EC=A0=81=20flush=20=EB=8C=80=EC=8B=A0=20=EB=B2=8C?= =?UTF-8?q?=ED=81=AC=20=EC=BF=BC=EB=A6=AC=EC=9D=98=20flushAutomatically=20?= =?UTF-8?q?=EB=AA=A8=EB=93=9C=EB=A5=BC=20true=EB=A1=9C=20=EC=84=A4?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../woowacourse/f12/application/review/ReviewService.java | 3 --- .../woowacourse/f12/domain/product/ProductRepository.java | 6 +++--- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/backend/src/main/java/com/woowacourse/f12/application/review/ReviewService.java b/backend/src/main/java/com/woowacourse/f12/application/review/ReviewService.java index ed3fbff7..a3307577 100644 --- a/backend/src/main/java/com/woowacourse/f12/application/review/ReviewService.java +++ b/backend/src/main/java/com/woowacourse/f12/application/review/ReviewService.java @@ -113,7 +113,6 @@ public void update(final Long reviewId, final Long memberId, final ReviewRequest final Review updateReview = updateRequest.toReview(target.getProduct(), target.getMember()); int ratingGap = updateReview.getRating() - target.getRating(); target.update(updateReview); - reviewRepository.flush(); productRepository.updateProductStatisticsForReviewUpdate(target.getProduct().getId(), ratingGap); } @@ -125,8 +124,6 @@ public void delete(final Long reviewId, final Long memberId) { .orElseThrow(InventoryProductNotFoundException::new); inventoryProductRepository.delete(inventoryProduct); reviewRepository.delete(review); -// inventoryProductRepository.flush(); - reviewRepository.flush(); productRepository.updateProductStatisticsForReviewDelete(review.getProduct().getId(), review.getRating()); } diff --git a/backend/src/main/java/com/woowacourse/f12/domain/product/ProductRepository.java b/backend/src/main/java/com/woowacourse/f12/domain/product/ProductRepository.java index 7d275596..9217606d 100644 --- a/backend/src/main/java/com/woowacourse/f12/domain/product/ProductRepository.java +++ b/backend/src/main/java/com/woowacourse/f12/domain/product/ProductRepository.java @@ -9,7 +9,7 @@ public interface ProductRepository extends JpaRepository, Product List findByReviewCountGreaterThanEqualAndRatingGreaterThanEqual(int reviewCount, double rating); - @Modifying(clearAutomatically = true) + @Modifying(clearAutomatically = true, flushAutomatically = true) @Query(value = "update Product p " + "set p.rating = (p.totalRating + :reviewRating) / cast((p.reviewCount + 1) as double), " + "p.reviewCount = p.reviewCount + 1, " @@ -17,7 +17,7 @@ public interface ProductRepository extends JpaRepository, Product + "where p.id = :productId") void updateProductStatisticsForReviewInsert(Long productId, int reviewRating); - @Modifying(clearAutomatically = true) + @Modifying(clearAutomatically = true, flushAutomatically = true) @Query(value = "update Product p " + "set p.rating = case p.reviewCount when 1 then 0 " + "else ((p.totalRating - :reviewRating) / cast((p.reviewCount - 1) as double)) end , " @@ -26,7 +26,7 @@ public interface ProductRepository extends JpaRepository, Product + "where p.id = :productId") void updateProductStatisticsForReviewDelete(Long productId, int reviewRating); - @Modifying(clearAutomatically = true) + @Modifying(clearAutomatically = true, flushAutomatically = true) @Query(value = "update Product p " + "set p.rating = (p.totalRating + :ratingGap) / cast(p.reviewCount as double), " + "p.totalRating = p.totalRating + :ratingGap " From c3e354dc0ac1efd41ea1d955ee920d82f12de529 Mon Sep 17 00:00:00 2001 From: Ohzzi Date: Mon, 17 Oct 2022 20:48:15 +0900 Subject: [PATCH 3/3] =?UTF-8?q?feat:=201=EC=8B=9C=EA=B0=84=EB=A7=88?= =?UTF-8?q?=EB=8B=A4=20=ED=9A=8C=EC=9B=90=EC=9D=98=20=ED=8C=94=EB=A1=9C?= =?UTF-8?q?=EC=9B=8C=20=EC=88=98=20=EC=A0=95=ED=95=A9=EC=84=B1=EC=9D=84=20?= =?UTF-8?q?=EB=A7=9E=EC=B6=94=EB=8A=94=20=EB=B0=B0=EC=B9=98=20=EC=BF=BC?= =?UTF-8?q?=EB=A6=AC=EB=A5=BC=20=EC=8B=A4=ED=96=89=ED=95=98=EB=8A=94=20?= =?UTF-8?q?=EC=8A=A4=EC=BC=80=EC=A4=84=EB=9F=AC=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../f12/application/batch/BatchService.java | 20 +++++++++++++++ .../batch/FollowerCountBatchScheduler.java | 25 +++++++++++++++++++ .../f12/config/SchedulerConfig.java | 23 +++++++++++++++++ 3 files changed, 68 insertions(+) create mode 100644 backend/src/main/java/com/woowacourse/f12/application/batch/BatchService.java create mode 100644 backend/src/main/java/com/woowacourse/f12/application/batch/FollowerCountBatchScheduler.java create mode 100644 backend/src/main/java/com/woowacourse/f12/config/SchedulerConfig.java diff --git a/backend/src/main/java/com/woowacourse/f12/application/batch/BatchService.java b/backend/src/main/java/com/woowacourse/f12/application/batch/BatchService.java new file mode 100644 index 00000000..309f53cb --- /dev/null +++ b/backend/src/main/java/com/woowacourse/f12/application/batch/BatchService.java @@ -0,0 +1,20 @@ +package com.woowacourse.f12.application.batch; + +import com.woowacourse.f12.domain.member.MemberRepository; +import org.springframework.stereotype.Component; +import org.springframework.transaction.annotation.Transactional; + +@Component +public class BatchService { + + private final MemberRepository memberRepository; + + public BatchService(final MemberRepository memberRepository) { + this.memberRepository = memberRepository; + } + + @Transactional + public void updateFollowerCount() { + memberRepository.updateFollowerCountBatch(); + } +} diff --git a/backend/src/main/java/com/woowacourse/f12/application/batch/FollowerCountBatchScheduler.java b/backend/src/main/java/com/woowacourse/f12/application/batch/FollowerCountBatchScheduler.java new file mode 100644 index 00000000..0caaed3a --- /dev/null +++ b/backend/src/main/java/com/woowacourse/f12/application/batch/FollowerCountBatchScheduler.java @@ -0,0 +1,25 @@ +package com.woowacourse.f12.application.batch; + +import lombok.extern.slf4j.Slf4j; +import org.springframework.scheduling.annotation.Scheduled; + +@Slf4j +public class FollowerCountBatchScheduler { + + private static final String LOG_FORMAT = "Class : {}, Message : {}"; + + private final BatchService batchService; + + public FollowerCountBatchScheduler(final BatchService batchService) { + this.batchService = batchService; + } + + @Scheduled(cron = "0 0 0/1 1/1 * ? *") + public void execute() { + try { + batchService.updateFollowerCount(); + } catch (Exception e) { + log.error(LOG_FORMAT, e.getClass().getSimpleName(), e.getMessage()); + } + } +} diff --git a/backend/src/main/java/com/woowacourse/f12/config/SchedulerConfig.java b/backend/src/main/java/com/woowacourse/f12/config/SchedulerConfig.java new file mode 100644 index 00000000..a8b9a0ff --- /dev/null +++ b/backend/src/main/java/com/woowacourse/f12/config/SchedulerConfig.java @@ -0,0 +1,23 @@ +package com.woowacourse.f12.config; + +import com.woowacourse.f12.application.batch.BatchService; +import com.woowacourse.f12.application.batch.FollowerCountBatchScheduler; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.scheduling.annotation.EnableScheduling; + +@EnableScheduling +@Configuration +public class SchedulerConfig { + + private final BatchService batchService; + + public SchedulerConfig(final BatchService batchService) { + this.batchService = batchService; + } + + @Bean(name = "followerCountBatchScheduler") + public FollowerCountBatchScheduler followerCountBatchScheduler() { + return new FollowerCountBatchScheduler(batchService); + } +}