diff --git a/src/main/java/com/devkor/ifive/nadab/domain/dailyreport/core/service/AnswerEntryService.java b/src/main/java/com/devkor/ifive/nadab/domain/dailyreport/core/service/AnswerEntryService.java index 27d8675..04ab19b 100644 --- a/src/main/java/com/devkor/ifive/nadab/domain/dailyreport/core/service/AnswerEntryService.java +++ b/src/main/java/com/devkor/ifive/nadab/domain/dailyreport/core/service/AnswerEntryService.java @@ -7,8 +7,8 @@ import com.devkor.ifive.nadab.global.shared.util.TodayDateTimeProvider; import com.devkor.ifive.nadab.global.shared.util.dto.TodayDateTimeRangeDto; import lombok.RequiredArgsConstructor; +import org.springframework.dao.DataIntegrityViolationException; import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Propagation; import org.springframework.transaction.annotation.Transactional; import java.time.LocalDate; @@ -21,15 +21,24 @@ public class AnswerEntryService { private final AnswerEntryRepository answerEntryRepository; - @Transactional(propagation = Propagation.REQUIRES_NEW) + @Transactional public AnswerEntry getOrCreateTodayAnswerEntry(User user, DailyQuestion dq, String answerText) { TodayDateTimeRangeDto range = TodayDateTimeProvider.getRange(); LocalDate today = TodayDateTimeProvider.getTodayDate(); - return answerEntryRepository.findByUserAndCreatedAtBetween(user, range.startOfToday(), range.startOfTomorrow()) - .orElseGet(() -> answerEntryRepository.save(AnswerEntry.create(user, dq, answerText, today))); + return answerEntryRepository. + findByUserAndCreatedAtBetween(user, range.startOfToday(), range.startOfTomorrow()) + .orElseGet(() -> { + try { + return answerEntryRepository.save(AnswerEntry.create(user, dq, answerText, today)); + } catch (DataIntegrityViolationException e) { + // 동시 요청에서 이미 누가 만들었을 수 있음 -> 재조회로 멱등 처리 + return answerEntryRepository.findByUserAndCreatedAtBetween(user, range.startOfToday(), range.startOfTomorrow()) + .orElseThrow(() -> e); + } + }); } } diff --git a/src/main/java/com/devkor/ifive/nadab/domain/dailyreport/core/service/PendingDailyReportService.java b/src/main/java/com/devkor/ifive/nadab/domain/dailyreport/core/service/PendingDailyReportService.java index 6b85967..5fe7037 100644 --- a/src/main/java/com/devkor/ifive/nadab/domain/dailyreport/core/service/PendingDailyReportService.java +++ b/src/main/java/com/devkor/ifive/nadab/domain/dailyreport/core/service/PendingDailyReportService.java @@ -9,8 +9,8 @@ import com.devkor.ifive.nadab.global.shared.util.TodayDateTimeProvider; import com.devkor.ifive.nadab.global.shared.util.dto.TodayDateTimeRangeDto; import lombok.RequiredArgsConstructor; +import org.springframework.dao.DataIntegrityViolationException; import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Propagation; import org.springframework.transaction.annotation.Transactional; import java.time.LocalDate; @@ -23,15 +23,24 @@ public class PendingDailyReportService { private final DailyReportRepository dailyReportRepository; - @Transactional(propagation = Propagation.REQUIRES_NEW) + @Transactional public DailyReport getOrCreatePendingDailyReport(AnswerEntry entry) { TodayDateTimeRangeDto range = TodayDateTimeProvider.getRange(); LocalDate today = TodayDateTimeProvider.getTodayDate(); - DailyReport report = dailyReportRepository.findByAnswerEntryAndCreatedAtBetween(entry, range.startOfToday(), range.startOfTomorrow()) - .orElseGet(() -> dailyReportRepository.save(DailyReport.createPending(entry, today))); + DailyReport report = dailyReportRepository. + findByAnswerEntryAndCreatedAtBetween(entry, range.startOfToday(), range.startOfTomorrow()) + .orElseGet(() -> { + try { + return dailyReportRepository.save(DailyReport.createPending(entry, today)); + } catch (DataIntegrityViolationException e) { + // 동시 요청에서 이미 누가 만들었을 수 있음 -> 재조회로 멱등 처리 + return dailyReportRepository.findByAnswerEntryAndCreatedAtBetween(entry, range.startOfToday(), range.startOfTomorrow()) + .orElseThrow(() -> e); + } + }); if (report.getStatus() == DailyReportStatus.COMPLETED) { throw new ConflictException(ErrorCode.DAILY_REPORT_ALREADY_COMPLETED);