목적

사용 기술

트랜잭션 롤백 프로세스 설계 및 구현

게시글 수정 API

<aside> ✅ 롤백 프로세스

1단계) DB에서 게시글 내용 변경 실패 시 : 1단계 롤백

2단계) DB에서 기존 이미지 삭제 실패 시 : 1단계 + 2단계 롤백

3단계) DB에서 새로운 이미지 등록 실패 시 : 1단계 + 2단계 + 3단계 롤백

4단계) AWS S3에 새로운 이미지 파일 업로드 실패 시 : 1단계 + 2단계 + 3단계 롤백

5단계) AWS S3에서 기존 이미지 파일 삭제 실패 시 : 1단계 + 2단계 + 3단계 롤백 + AWS S3에 업로드한 새로운 이미지 파일 삭제

</aside>

서비스 계층 : @Transactional을 사용해 롤백 적용

@Service
@RequiredArgsConstructor
public class PostService {

		/* 8. 게시글 수정 API */
****    @Transactional(rollbackFor = {Exception.class})
    public String modifyPost(Long postIdx, String content, List<MultipartFile> multipartFile, List<Integer> imageNumberlist, Long userIdx) throws BasicException {

        Post postBefore = postDao.findByIdx(postIdx);
        List<PostImage> PostImageBeforeList = postImageDao.findByPost(postBefore);

        //게시글 삭제 여부 조회 (생략)
        //게시글 작성자 일치 여부 확인 (생략)
        
        **//1단계) 게시글 내용 변경**
        if(content != null) {
            try {
                postBefore.updateContent(content);
            } catch (Exception exception) {
                throw new BasicException(DATABASE_ERROR_MODIFY_FAIL_POSTS_CONTENT);   //"게시글 내용 변경 오류"
            }
        }

				**//2단계) DB에서 기존 이미지 삭제**
        List<PostImage> postImageListBefore = postBefore.getPostImages();
        postImageListBefore.forEach(postImage -> {
            postImage.deletePostImage();
        });;

        **//3단계) DB에 새로운 게시글 이미지 등록**
        List<String> UUID_fileNameList = new ArrayList<>();;
        List<PostImage> postImageListCreation = new ArrayList<>();

        if(imageNumberlist != null) {
            try {
                //DB에 새로운 이미지 등록
                for(int i=0; i<imageNumberlist.size(); i++) {
                    UUID_fileNameList.add(awsS3Service.createFileNameToDB(multipartFile.get(i)));         //UUID가 적용된 새로운 이미지 파일명 리턴

										PostImage postImageCreation = PostImage.builder()
                            .image(Secret.AWS_S3_CONNECT_URL+UUID_fileNameList.get(i))
                            .imageNumber(imageNumberlist.get(i))
                            .post(postBefore)
                            .build();

                    postImageListCreation.add(postImageCreation);
                }
                postImageDao.saveAll(postImageListCreation);
            }
            catch (Exception exception) {
                throw new BasicException(DATABASE_ERROR_MODIFY_FAIL_POSTS_IMAGE);   //"게시글 이미지 변경 오류"
            }

            **//4단계) S3에 새로운 이미지 파일 업로드**
            for(int i=0; i<imageNumberlist.size(); i++) {
                URI imageUrl = awsS3Service.uploadFile(multipartFile.get(i), UUID_fileNameList.get(i));  //이미지 파일과 UUID가 적용된 파일명 인수로 전달
            }

            **//5단계) S3에서 기존 이미지 파일 삭제**
            try {
                for(int i=0; i<PostImageBeforeList.size(); i++) {
                    String beforeS3_fileName = PostImageBeforeList.get(i).getImage().replace(Secret.AWS_S3_CONNECT_URL, "");
                    awsS3Service.deleteFile(beforeS3_fileName);
                }
            }
            catch(Exception exception){    //이전 이미지 파일 삭제 실패시 업로드된 새로운 파일을 삭제
                for(int i=0; i<imageNumberlist.size(); i++) {
                    awsS3Service.deleteFile(UUID_fileNameList.get(i));
                }
                throw new BasicException(S3_ERROR_FAIL_DELETE_FILE);  //"S3에서 파일 삭제 실패"
            }
        }
        return "게시글 수정 성공";
    }

}

🖥️ 참고) 게시글 수정 API 실행 결과

Untitled