결제하지 않은 주문 목록 다음 주문할 때 삭제되도록 하였지만 → 다음 주문하지 않으면 저장된 주문데이터가 그대로 남아있는 문제가 있다.
주문 데이터 삭제하면 주문에 딸린 주문상품목록도 함께 삭제된다.
-> order가 100만개 - order item이 order당 3개로 300만개 총 400만 건에 대한 데이터 테스트
@Override //스케줄러로 주기적으로 삭제
@Transactional // 주문 상태 ORDER 인 주문 목록 일괄 삭제
public void deleteOrdersInBatches(OrderStatus status, int batchSize) {
int deletedCount = 0;
int batchDeleted;
long startTime = System.currentTimeMillis();
log.info("Starting deletion of orders with status {} in batches of {}", status, batchSize);
try {
do {
batchDeleted = orderRepository.deleteBatchByStatus(status); // 주문 삭제
deletedCount += batchDeleted;
log.info("Deleted batch of {} orders", batchDeleted);
} while (batchDeleted >= batchSize);
// Record the end time
long endTime = System.currentTimeMillis();
long duration = endTime - startTime;
log.info("Successfully deleted {} orders with status {}. Time taken: {} ms",
deletedCount, status, duration);
} catch (Exception e) {
log.error("An error occurred while deleting orders: {}", e.getMessage());
throw e;
}
}
/**
* 주문 상태 ORDER 인 주문 목록 하루에 한 번씩 삭제
*/
@Configuration
@RequiredArgsConstructor
public class OrderCleanUpConfig {
private final OrderService orderService;
@Bean
public Job orderCleanupJob(JobRepository jobRepository, Step orderCleanupStep) {
return new JobBuilder("orderCleanupJob", jobRepository)
.incrementer(new RunIdIncrementer())
.start(orderCleanupStep)
.build();
}
@JobScope
@Bean
public Step orderCleanupStep(JobRepository jobRepository,
PlatformTransactionManager transactionManager,
Tasklet orderCleanupTasklet) {
return new StepBuilder("orderCleanupStep", jobRepository)
.tasklet(orderCleanupTasklet, transactionManager)
.build();
}
@StepScope
@Bean
public Tasklet orderCleanupTasklet() {
return (contribution, chunkContext) -> {
orderService.deleteOrdersInBatches(OrderStatus.ORDER, 100);
return RepeatStatus.FINISHED;
};
}
}
public interface OrderRepository extends JpaRepository<Order, Long> {
@Modifying // ORDER 주문 목록 전체 삭제
@Query("DELETE FROM Order o WHERE o.orderStatus = :status")
int deleteBatchByStatus(@Param("status") OrderStatus status); // 삭제된 행 수 반환
}
@Component
@RequiredArgsConstructor
public class Scheduler {
private final Job orderCleanupJob;
private final JobLauncher jobLauncher;
//@Scheduled(cron = "0 */1 * * * *") // 1분마다
@Scheduled(cron = "0 0 4 * * *") // 하루에 한번
public void orderCleanupJobRun()
throws JobInstanceAlreadyCompleteException,
JobExecutionAlreadyRunningException,
JobParametersInvalidException,
JobRestartException {
JobParameters jobParameters = new JobParametersBuilder()
.addLong("requestTime", Instant.now().toEpochMilli())
.toJobParameters();
jobLauncher.run(orderCleanupJob, jobParameters);
}
}
SpringDataJpa에서 deleteByxxx 등의 메소드 사용시
• 삭제 대상들을 전부 조회하는 쿼리가 1번 발생한다.
• 삭제 대상들은 1건씩 삭제된다.
• cascade = CascadeType.DELETE 으로 하위 엔티티와 관계가 맺어진 경우 하위 엔티티들도 1건씩 삭제가 진행된다.
@Modifying // ORDER 주문 목록 전체 삭제
@Query("DELETE FROM Order o WHERE o.orderStatus = :status")
int deleteBatchByStatus(@Param("status") OrderStatus status); // 삭제된 행 수 반환
대규모 데이터 처리 시 발생할 수 있는 메모리 부하를 방지하기 위해 적절한 배치 사이즈를 설정하여 청크 단위로 삭제를 수행하도록 했다.