Skip to content

Commit

Permalink
[hotfix]: 긴급 공지 상태 변경
Browse files Browse the repository at this point in the history
  • Loading branch information
qogustj committed Oct 7, 2024
1 parent 69f9bda commit 8302790
Show file tree
Hide file tree
Showing 7 changed files with 106 additions and 108 deletions.

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,9 @@ public class QStudentCsvEntity extends EntityPathBase<StudentCsvEntity> {

public final StringPath major = createString("major");

public final NumberPath<Long> STID = createNumber("STID", Long.class);
public final StringPath program = createString("program");

public final StringPath studentEmail = createString("studentEmail");

public final StringPath studentGroup = createString("studentGroup");
public final StringPath specificMajor = createString("specificMajor");

public final NumberPath<Long> studentId = createNumber("studentId", Long.class);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ public interface PostRepository {
Page<Post> findAllByBoardIdAndCategory(Long boardId, Category category, Pageable pageable);
Post save(Post post);
void updatePostStatusNewToGeneral(LocalDateTime dueDateOfNew);
void updatePostStatusEmergencyToGeneralInBatches();
void delete(Post post);
Page<Post> findBySearchCriteria(Pageable pageable,String boardCode, String q, String categoryCode);
Page<SimplePostResponse> findPostDtoListByBoardCode(String boardCode, Pageable pageable);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,10 @@
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import ussum.homepage.domain.post.PostRepository;
import ussum.homepage.infra.jpa.post.entity.PostEntity;

import java.time.LocalDateTime;
import java.util.List;

@Service
@RequiredArgsConstructor
Expand All @@ -19,4 +21,57 @@ public void updatePostStatusNewToGeneral() {
LocalDateTime dueDateOfNew = LocalDateTime.now().minusDays(3);
postRepository.updatePostStatusNewToGeneral(dueDateOfNew);
}

/**
메모리 효율성:
IN 쿼리 방식: 모든 대상 엔티티를 한 번에 메모리에 로드하므로 대량의 데이터 처리 시 OutOfMemoryError 발생 가능성이 있습니다.
단일 UPDATE 방식: 서버 측 메모리 사용은 적지만, DB 서버에서 큰 부하가 발생할 수 있습니다.
배치 처리 방식: 한 번에 제한된 수의 레코드만 처리하므로 메모리 사용을 효과적으로 제어할 수 있습니다.
데이터베이스 부하:
IN 쿼리 방식: 많은 데이터를 한 번에 조회하므로 DB에 순간적으로 큰 부하를 줄 수 있습니다.
단일 UPDATE 방식: 대량의 레코드를 한 번에 업데이트하여 DB에 극심한 부하를 줄 수 있습니다.
배치 처리 방식: 작업을 작은 단위로 나누어 실행하므로 DB 부하를 분산시킬 수 있습니다.
트랜잭션 관리:
IN 쿼리 방식: 모든 업데이트가 하나의 큰 트랜잭션에서 이루어져, 롤백 시 모든 변경사항이 취소됩니다.
단일 UPDATE 방식: 하나의 대규모 트랜잭션으로 인해 롤백 시 많은 시간이 소요될 수 있습니다.
배치 처리 방식: 작은 트랜잭션들로 나누어 처리하므로, 문제 발생 시 해당 배치만 롤백되어 리스크를 줄일 수 있습니다.
락(Lock) 관리:
IN 쿼리 방식: 많은 레코드를 동시에 락을 걸 수 있어 다른 트랜잭션을 차단할 수 있습니다.
단일 UPDATE 방식: 대량의 레코드에 대해 동시에 락을 획득하여 다른 작업을 오랫동안 차단할 수 있습니다.
배치 처리 방식: 소수의 레코드만 짧은 시간 동안 락을 걸기 때문에 다른 트랜잭션과의 충돌 가능성이 낮습니다.
에러 처리와 재시도:
IN 쿼리 방식: 전체 프로세스 중 오류 발생 시 어떤 레코드가 처리되었는지 파악하기 어렵습니다.
단일 UPDATE 방식: 오류 발생 시 전체 작업이 실패하며, 부분적 성공을 처리하기 어렵습니다.
배치 처리 방식: 각 배치별로 오류를 독립적으로 처리할 수 있어, 실패한 배치만 재시도할 수 있습니다.
진행 상황 모니터링:
IN 쿼리와 단일 UPDATE 방식: 전체 작업의 진행 상황을 중간에 확인하기 어렵습니다.
배치 처리 방식: 각 배치마다 처리된 레코드 수를 확인할 수 있어 진행 상황을 실시간으로 모니터링할 수 있습니다.
시스템 리소스 활용:
배치 처리 방식은 시스템 리소스를 더 균형있게 사용할 수 있게 해주며, 다른 작업과의 리소스 경쟁을 줄일 수 있습니다.
**/
@Scheduled(cron = "0 0 0 * * ?")
@Transactional
public void updatePostStatusToGeneral() {
postRepository.updatePostStatusEmergencyToGeneralInBatches();
System.out.println("게시물 상태 업데이트 작업이 실행되었습니다. - " + LocalDateTime.now());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import com.querydsl.jpa.JPAExpressions;
import com.querydsl.jpa.impl.JPAQuery;
import com.querydsl.jpa.impl.JPAQueryFactory;
import jakarta.persistence.EntityManager;
import lombok.RequiredArgsConstructor;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
Expand Down Expand Up @@ -69,6 +70,7 @@ public class PostRepositoryImpl implements PostRepository {
private final JPAQueryFactory queryFactory;
private final PostReplyCommentJpaRepository postReplyCommentJpaRepository;
private final PostCommentJpaRepository postCommentJpaRepository;
private final EntityManager entityManager;

@Override
public Optional<Post> findById(Long postId) {
Expand Down Expand Up @@ -570,4 +572,47 @@ public void updatePostStatusNewToGeneral(LocalDateTime dueDateForNewStatus) {
.and(postEntity.createdAt.loe(dueDateForNewStatus)))
.execute();
}

@Override
public void updatePostStatusEmergencyToGeneralInBatches() {
// 3일 전 날짜 계산
LocalDateTime threeDaysAgo = LocalDateTime.now().minusDays(3);
// 한 번에 처리할 게시물 수 설정
int batchSize = 500;
// 총 처리된 게시물 수를 추적하기 위한 변수
long processedCount = 0;

while (true) {
// 배치 크기만큼의 게시물 ID를 가져옴
List<Long> batchIds = queryFactory
.select(postEntity.id)
.from(postEntity)
.where(postEntity.boardEntity.id.eq(2L) // 공지사항 게시판 ID가 1이라고 가정
.and(postEntity.status.ne(Status.GENERAL)) // 상태가 GENERAL이 아닌 것
.and(postEntity.createdAt.before(threeDaysAgo))) // 3일 이전에 생성된 것
.limit(batchSize)
.fetch();

// 더 이상 처리할 게시물이 없으면 반복 종료
if (batchIds.isEmpty()) {
break;
}

// 가져온 ID에 해당하는 게시물들의 상태를 GENERAL로 업데이트
long updatedCount = queryFactory
.update(postEntity)
.set(postEntity.status, Status.GENERAL)
.where(postEntity.id.in(batchIds))
.execute();

// 처리된 게시물 수 누적
processedCount += updatedCount;

// 영속성 컨텍스트 초기화 (메모리 관리를 위해)
entityManager.clear();
}

// 총 처리된 게시물 수 출력
System.out.println("총 업데이트된 게시물 수: " + processedCount);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -61,4 +61,7 @@ public void updateCategory(Category newCategory) {
this.category = newCategory;
// this.ongoingStatus = newStatus;
}
public void updateStatus(Status newStatus) {
this.status = newStatus;
}
}

0 comments on commit 8302790

Please sign in to comment.