From 64b8199408de9c37db6079ceb41a795cc47448b2 Mon Sep 17 00:00:00 2001 From: wjddn2165 Date: Fri, 23 Aug 2024 02:29:12 +0900 Subject: [PATCH 1/3] =?UTF-8?q?feat:=20BaseUser=20=EC=9D=98=20phoneNumber?= =?UTF-8?q?=20=ED=95=84=EB=93=9C=EC=97=90=20=EC=9D=B8=EB=8D=B1=EC=8A=A4?= =?UTF-8?q?=EB=A5=BC=20=EC=B6=94=EA=B0=80=ED=95=98=EB=8F=84=EB=A1=9D=20?= =?UTF-8?q?=EC=84=A4=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Server/src/main/java/JGS/CasperEvent/global/entity/BaseUser.java | 1 + 1 file changed, 1 insertion(+) diff --git a/Server/src/main/java/JGS/CasperEvent/global/entity/BaseUser.java b/Server/src/main/java/JGS/CasperEvent/global/entity/BaseUser.java index 21dbda9c..9cbbe0ac 100644 --- a/Server/src/main/java/JGS/CasperEvent/global/entity/BaseUser.java +++ b/Server/src/main/java/JGS/CasperEvent/global/entity/BaseUser.java @@ -22,6 +22,7 @@ public class BaseUser extends BaseEntity { @GeneratedValue(strategy = GenerationType.IDENTITY) Long id; + @Column(unique = true) String phoneNumber; Role role; From b6637deb110befff6ac5a7e865f35beb8b3fda25 Mon Sep 17 00:00:00 2001 From: wjddn2165 Date: Fri, 23 Aug 2024 02:32:01 +0900 Subject: [PATCH 2/3] =?UTF-8?q?refactor:=20=EA=B8=B0=EC=A1=B4=20redisServi?= =?UTF-8?q?ce=20->=20LotteryEventRedisService=20=EC=9D=B4=EB=A6=84=20?= =?UTF-8?q?=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../eventController/LotteryEventController.java | 10 +++++----- .../service/eventService/LotteryEventService.java | 6 +++--- ...RedisService.java => LotteryEventRedisService.java} | 4 ++-- .../eventController/LotteryEventControllerTest.java | 7 +++---- .../service/eventService/LotteryEventServiceTest.java | 4 ++-- 5 files changed, 15 insertions(+), 16 deletions(-) rename Server/src/main/java/JGS/CasperEvent/domain/event/service/redisService/{RedisService.java => LotteryEventRedisService.java} (88%) diff --git a/Server/src/main/java/JGS/CasperEvent/domain/event/controller/eventController/LotteryEventController.java b/Server/src/main/java/JGS/CasperEvent/domain/event/controller/eventController/LotteryEventController.java index 58bb8abd..69b62cc2 100644 --- a/Server/src/main/java/JGS/CasperEvent/domain/event/controller/eventController/LotteryEventController.java +++ b/Server/src/main/java/JGS/CasperEvent/domain/event/controller/eventController/LotteryEventController.java @@ -4,7 +4,7 @@ import JGS.CasperEvent.domain.event.dto.ResponseDto.lotteryEventResponseDto.CasperBotResponseDto; import JGS.CasperEvent.domain.event.dto.ResponseDto.lotteryEventResponseDto.LotteryEventResponseDto; import JGS.CasperEvent.domain.event.dto.ResponseDto.lotteryEventResponseDto.LotteryParticipantResponseDto; -import JGS.CasperEvent.domain.event.service.redisService.RedisService; +import JGS.CasperEvent.domain.event.service.redisService.LotteryEventRedisService; import JGS.CasperEvent.domain.event.service.eventService.LotteryEventService; import JGS.CasperEvent.global.entity.BaseUser; import io.swagger.v3.oas.annotations.Operation; @@ -31,12 +31,12 @@ public class LotteryEventController { private final LotteryEventService lotteryEventService; - private final RedisService redisService; + private final LotteryEventRedisService lotteryEventRedisService; @Autowired - public LotteryEventController(LotteryEventService lotteryEventService, RedisService redisService) { + public LotteryEventController(LotteryEventService lotteryEventService, LotteryEventRedisService lotteryEventRedisService) { this.lotteryEventService = lotteryEventService; - this.redisService = redisService; + this.lotteryEventRedisService = lotteryEventRedisService; } @Operation(summary = "추첨 이벤트 조회", description = "현재 진행 중인 추첨 이벤트의 정보를 조회합니다.") @@ -88,6 +88,6 @@ public ResponseEntity getLotteryParticipant(HttpS @GetMapping("/caspers") public ResponseEntity> getCasperBots() { return ResponseEntity.status(HttpStatus.OK) - .body(redisService.getRecentData()); + .body(lotteryEventRedisService.getRecentData()); } } diff --git a/Server/src/main/java/JGS/CasperEvent/domain/event/service/eventService/LotteryEventService.java b/Server/src/main/java/JGS/CasperEvent/domain/event/service/eventService/LotteryEventService.java index 4d233348..4efc8ce6 100644 --- a/Server/src/main/java/JGS/CasperEvent/domain/event/service/eventService/LotteryEventService.java +++ b/Server/src/main/java/JGS/CasperEvent/domain/event/service/eventService/LotteryEventService.java @@ -7,7 +7,7 @@ import JGS.CasperEvent.domain.event.entity.participants.LotteryParticipants; import JGS.CasperEvent.domain.event.repository.CasperBotRepository; import JGS.CasperEvent.domain.event.repository.participantsRepository.LotteryParticipantsRepository; -import JGS.CasperEvent.domain.event.service.redisService.RedisService; +import JGS.CasperEvent.domain.event.service.redisService.LotteryEventRedisService; import JGS.CasperEvent.global.entity.BaseUser; import JGS.CasperEvent.global.enums.CustomErrorCode; import JGS.CasperEvent.global.error.exception.CustomException; @@ -37,7 +37,7 @@ public class LotteryEventService { private final UserRepository userRepository; private final LotteryParticipantsRepository lotteryParticipantsRepository; private final CasperBotRepository casperBotRepository; - private final RedisService redisService; + private final LotteryEventRedisService lotteryEventRedisService; private final SecretKey secretKey; private final EventCacheService eventCacheService; @@ -57,7 +57,7 @@ public CasperBotResponseDto postCasperBot(BaseUser user, CasperBotRequestDto cas } CasperBotResponseDto casperBotDto = CasperBotResponseDto.of(casperBot); - redisService.addData(casperBotDto); + lotteryEventRedisService.addData(casperBotDto); return casperBotDto; } diff --git a/Server/src/main/java/JGS/CasperEvent/domain/event/service/redisService/RedisService.java b/Server/src/main/java/JGS/CasperEvent/domain/event/service/redisService/LotteryEventRedisService.java similarity index 88% rename from Server/src/main/java/JGS/CasperEvent/domain/event/service/redisService/RedisService.java rename to Server/src/main/java/JGS/CasperEvent/domain/event/service/redisService/LotteryEventRedisService.java index 3de8b601..bce9090c 100644 --- a/Server/src/main/java/JGS/CasperEvent/domain/event/service/redisService/RedisService.java +++ b/Server/src/main/java/JGS/CasperEvent/domain/event/service/redisService/LotteryEventRedisService.java @@ -8,14 +8,14 @@ import java.util.List; @Service -public class RedisService { +public class LotteryEventRedisService { private static final String LIST_KEY = "recentData"; private static final int MAX_SIZE = 100; private final RedisTemplate redisTemplate; @Autowired - public RedisService(RedisTemplate redisTemplate) { + public LotteryEventRedisService(RedisTemplate redisTemplate) { this.redisTemplate = redisTemplate; } diff --git a/Server/src/test/java/JGS/CasperEvent/domain/event/controller/eventController/LotteryEventControllerTest.java b/Server/src/test/java/JGS/CasperEvent/domain/event/controller/eventController/LotteryEventControllerTest.java index 3db38ba9..27813d42 100644 --- a/Server/src/test/java/JGS/CasperEvent/domain/event/controller/eventController/LotteryEventControllerTest.java +++ b/Server/src/test/java/JGS/CasperEvent/domain/event/controller/eventController/LotteryEventControllerTest.java @@ -8,7 +8,7 @@ import JGS.CasperEvent.domain.event.entity.participants.LotteryParticipants; import JGS.CasperEvent.domain.event.service.adminService.AdminService; import JGS.CasperEvent.domain.event.service.eventService.LotteryEventService; -import JGS.CasperEvent.domain.event.service.redisService.RedisService; +import JGS.CasperEvent.domain.event.service.redisService.LotteryEventRedisService; import JGS.CasperEvent.global.entity.BaseUser; import JGS.CasperEvent.global.enums.Role; import JGS.CasperEvent.global.jwt.service.UserService; @@ -23,7 +23,6 @@ import org.springframework.boot.test.context.TestConfiguration; import org.springframework.boot.test.mock.mockito.MockBean; import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Import; import org.springframework.http.MediaType; import org.springframework.test.web.servlet.MockMvc; import org.springframework.test.web.servlet.ResultActions; @@ -54,7 +53,7 @@ class LotteryEventControllerTest { @MockBean private AdminService adminService; @MockBean - private RedisService redisService; + private LotteryEventRedisService lotteryEventRedisService; private BaseUser user; private String phoneNumber; @@ -192,7 +191,7 @@ void getCasperBotsSuccessTest() throws Exception { for (int i = 0; i < 100; i++) { recentData.add(casperBotResponse); } - given(redisService.getRecentData()) + given(lotteryEventRedisService.getRecentData()) .willReturn(recentData); //when diff --git a/Server/src/test/java/JGS/CasperEvent/domain/event/service/eventService/LotteryEventServiceTest.java b/Server/src/test/java/JGS/CasperEvent/domain/event/service/eventService/LotteryEventServiceTest.java index 589d67e6..61723861 100644 --- a/Server/src/test/java/JGS/CasperEvent/domain/event/service/eventService/LotteryEventServiceTest.java +++ b/Server/src/test/java/JGS/CasperEvent/domain/event/service/eventService/LotteryEventServiceTest.java @@ -10,7 +10,7 @@ import JGS.CasperEvent.domain.event.repository.CasperBotRepository; import JGS.CasperEvent.domain.event.repository.eventRepository.LotteryEventRepository; import JGS.CasperEvent.domain.event.repository.participantsRepository.LotteryParticipantsRepository; -import JGS.CasperEvent.domain.event.service.redisService.RedisService; +import JGS.CasperEvent.domain.event.service.redisService.LotteryEventRedisService; import JGS.CasperEvent.global.entity.BaseUser; import JGS.CasperEvent.global.enums.CustomErrorCode; import JGS.CasperEvent.global.enums.Role; @@ -52,7 +52,7 @@ class LotteryEventServiceTest { @Mock private CasperBotRepository casperBotRepository; @Mock - private RedisService redisService; + private LotteryEventRedisService lotteryEventRedisService; @InjectMocks From f1847ec9265ec27f37c823a710b27f7a498c98ad Mon Sep 17 00:00:00 2001 From: wjddn2165 Date: Fri, 23 Aug 2024 03:05:25 +0900 Subject: [PATCH 3/3] =?UTF-8?q?refactor:=20=EC=8B=A4=EC=8B=9C=EA=B0=84=20?= =?UTF-8?q?=EC=9D=91=EB=AA=A8=20=EB=B9=84=EC=9C=A8=20=EB=B0=98=ED=99=98=20?= =?UTF-8?q?=EB=A1=9C=EC=A7=81=EC=97=90=20Redis=20incr=20=ED=95=A8=EC=88=98?= =?UTF-8?q?=EB=A5=BC=20=EC=9D=B4=EC=9A=A9=ED=95=98=EC=97=AC=20=EC=BA=90?= =?UTF-8?q?=EC=8B=B1=ED=95=98=EB=8F=84=EB=A1=9D=20=EA=B0=9C=EC=84=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../eventService/RushEventService.java | 16 +++++- .../redisService/RushEventRedisService.java | 56 +++++++++++++++++++ 2 files changed, 69 insertions(+), 3 deletions(-) create mode 100644 Server/src/main/java/JGS/CasperEvent/domain/event/service/redisService/RushEventRedisService.java diff --git a/Server/src/main/java/JGS/CasperEvent/domain/event/service/eventService/RushEventService.java b/Server/src/main/java/JGS/CasperEvent/domain/event/service/eventService/RushEventService.java index a2a9ccce..c983a145 100644 --- a/Server/src/main/java/JGS/CasperEvent/domain/event/service/eventService/RushEventService.java +++ b/Server/src/main/java/JGS/CasperEvent/domain/event/service/eventService/RushEventService.java @@ -7,13 +7,13 @@ import JGS.CasperEvent.domain.event.repository.eventRepository.RushEventRepository; import JGS.CasperEvent.domain.event.repository.eventRepository.RushOptionRepository; import JGS.CasperEvent.domain.event.repository.participantsRepository.RushParticipantsRepository; +import JGS.CasperEvent.domain.event.service.redisService.RushEventRedisService; import JGS.CasperEvent.global.entity.BaseUser; import JGS.CasperEvent.global.enums.CustomErrorCode; import JGS.CasperEvent.global.enums.Position; import JGS.CasperEvent.global.error.exception.CustomException; import JGS.CasperEvent.global.util.RepositoryErrorHandler; import lombok.RequiredArgsConstructor; -import org.springframework.scheduling.annotation.Async; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -31,6 +31,7 @@ public class RushEventService { private final RushParticipantsRepository rushParticipantsRepository; private final RushOptionRepository rushOptionRepository; private final EventCacheService eventCacheService; + private final RushEventRedisService rushEventRedisService; @Transactional public RushEventListResponseDto getAllRushEvents() { @@ -83,6 +84,9 @@ public void apply(BaseUser user, int optionId) { // eventId 를 이용하여 rushEvent 를 꺼냄 RushEvent rushEvent = RepositoryErrorHandler.findByIdOrElseThrow(rushEventRepository, todayEventId, CustomErrorCode.NO_RUSH_EVENT); + // redis incr 호출 + rushEventRedisService.incrementOptionCount(todayEventId, optionId); + // 새로운 RushParticipants 를 생성하여 DB 에 저장 RushParticipants rushParticipants = new RushParticipants(user, rushEvent, optionId); rushParticipantsRepository.save(rushParticipants); @@ -93,8 +97,13 @@ public RushEventRateResponseDto getRushEventRate(BaseUser user) { LocalDate today = LocalDate.now(); Long todayEventId = eventCacheService.getTodayEvent(today).rushEventId(); Optional optionId = rushParticipantsRepository.getOptionIdByUserId(user.getPhoneNumber()); - long leftOptionCount = rushParticipantsRepository.countByRushEvent_RushEventIdAndOptionId(todayEventId, 1); - long rightOptionCount = rushParticipantsRepository.countByRushEvent_RushEventIdAndOptionId(todayEventId, 2); + +// long leftOptionCount = rushParticipantsRepository.countByRushEvent_RushEventIdAndOptionId(todayEventId, 1); +// long rightOptionCount = rushParticipantsRepository.countByRushEvent_RushEventIdAndOptionId(todayEventId, 2); + + // redis 에 캐싱 값 가져옴 + long leftOptionCount = rushEventRedisService.getOptionCount(todayEventId, 1); + long rightOptionCount = rushEventRedisService.getOptionCount(todayEventId, 2); return new RushEventRateResponseDto( optionId.orElseThrow(() -> new CustomException("유저가 응모한 선택지가 존재하지 않습니다.", CustomErrorCode.USER_NOT_FOUND)), @@ -227,6 +236,7 @@ public void setRushEvents() { eventCacheService.setCacheValue(LocalDate.now()); eventCacheService.setAllRushEvent(); + rushEventRedisService.clearAllrushEventRate(); } diff --git a/Server/src/main/java/JGS/CasperEvent/domain/event/service/redisService/RushEventRedisService.java b/Server/src/main/java/JGS/CasperEvent/domain/event/service/redisService/RushEventRedisService.java new file mode 100644 index 00000000..e3ffffe7 --- /dev/null +++ b/Server/src/main/java/JGS/CasperEvent/domain/event/service/redisService/RushEventRedisService.java @@ -0,0 +1,56 @@ +package JGS.CasperEvent.domain.event.service.redisService; + +import JGS.CasperEvent.domain.event.repository.participantsRepository.RushParticipantsRepository; +import lombok.RequiredArgsConstructor; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.stereotype.Service; + +import java.util.Set; + +@Service +@RequiredArgsConstructor +public class RushEventRedisService { + + private final RedisTemplate redisTemplate; + private final RushParticipantsRepository rushParticipantsRepository; + + public Long getOptionCount(Long eventId, int optionId) { + String redisKey = getRedisKey(eventId, optionId); + + // Redis에서 값 조회 + String cachedCount = redisTemplate.opsForValue().get(redisKey); + + if (cachedCount != null) { + // Redis에 값이 있으면 캐시된 값 반환 + return Long.valueOf(cachedCount); + } else { + // Redis에 값이 없으면 DB에서 값 조회 + long countFromDb = rushParticipantsRepository.countByRushEvent_RushEventIdAndOptionId(eventId, optionId); + + // 조회한 값을 Redis에 저장 + redisTemplate.opsForValue().set(redisKey, String.valueOf(countFromDb)); + + return countFromDb; + } + } + + public void incrementOptionCount(Long eventId, int optionId) { + String redisKey = getRedisKey(eventId, optionId); + + // Redis에서 해당 키의 값을 증가시킴 + redisTemplate.opsForValue().increment(redisKey); + } + + private String getRedisKey(Long eventId, int optionId) { + return "rushEvent:" + eventId + ":option:" + optionId; + } + + public void clearAllrushEventRate() { + // 특정 rushEventId에 대한 모든 옵션 키들을 가져와 삭제 + String pattern = "rushEvent:*" + ":option:*"; + Set keys = redisTemplate.keys(pattern); + if (keys != null && !keys.isEmpty()) { + redisTemplate.delete(keys); + } + } +}