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/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/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/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); + } + } +} 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; 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