Fix: 트랜잭션 처리
This commit is contained in:
parent
b94420a91f
commit
8649ae0a67
@ -11,7 +11,6 @@ import lombok.extern.slf4j.Slf4j;
|
|||||||
import org.springframework.scheduling.annotation.Async;
|
import org.springframework.scheduling.annotation.Async;
|
||||||
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
|
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import org.springframework.transaction.annotation.Isolation;
|
|
||||||
import org.springframework.transaction.annotation.Propagation;
|
import org.springframework.transaction.annotation.Propagation;
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
import org.springframework.web.multipart.MultipartFile;
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
@ -34,15 +33,14 @@ public class ImageAsyncService {
|
|||||||
log.debug("현재 스레드 - {} 업로드 파일 개수 - {}, 현재 작업 큐 용량 - {}",
|
log.debug("현재 스레드 - {} 업로드 파일 개수 - {}, 현재 작업 큐 용량 - {}",
|
||||||
Thread.currentThread().getName(),
|
Thread.currentThread().getName(),
|
||||||
imageFileList.size(),
|
imageFileList.size(),
|
||||||
imageUploadExecutor.getThreadPoolExecutor().getQueue().size()); // 큐에 쌓인 작업 수 출력);
|
imageUploadExecutor.getThreadPoolExecutor().getQueue().size()
|
||||||
|
); // 큐에 쌓인 작업 수 출력);
|
||||||
|
|
||||||
imageFileList.forEach(file -> {
|
imageFileList.forEach(file -> {
|
||||||
try{
|
try {
|
||||||
String extension = getExtension(file.getOriginalFilename());
|
String imageKey = imageUpload(projectId, file);
|
||||||
String imageKey = s3UploadService.uploadImageFile(file, extension, projectId);
|
|
||||||
|
|
||||||
createImage(file, imageKey, folder);
|
createImage(file, imageKey, folder);
|
||||||
}catch (Exception e){
|
} catch (Exception e) {
|
||||||
log.error("이미지 업로드 실패: {}", file.getOriginalFilename(), e);
|
log.error("이미지 업로드 실패: {}", file.getOriginalFilename(), e);
|
||||||
throw new CustomException(ErrorCode.FAIL_TO_CREATE_FILE);
|
throw new CustomException(ErrorCode.FAIL_TO_CREATE_FILE);
|
||||||
}
|
}
|
||||||
@ -52,15 +50,19 @@ public class ImageAsyncService {
|
|||||||
return CompletableFuture.completedFuture(null);
|
return CompletableFuture.completedFuture(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Transactional(propagation = Propagation.REQUIRES_NEW,isolation = Isolation.READ_COMMITTED)
|
@Transactional(propagation = Propagation.NOT_SUPPORTED)
|
||||||
|
public String imageUpload(Integer projectId, MultipartFile file) {
|
||||||
|
String extension = getExtension(file.getOriginalFilename());
|
||||||
|
return s3UploadService.uploadImageFile(file, extension, projectId);
|
||||||
|
}
|
||||||
|
|
||||||
public void createImage(MultipartFile file, String imageKey, Folder folder) {
|
public void createImage(MultipartFile file, String imageKey, Folder folder) {
|
||||||
try {
|
try {
|
||||||
String name = file.getOriginalFilename();
|
String name = file.getOriginalFilename();
|
||||||
String extension = getExtension(name);
|
String extension = getExtension(name);
|
||||||
log.debug("image 파일 {} {} {} {}", name, extension, imageKey, folder.getId());
|
|
||||||
Image image = Image.of(name, imageKey, extension, folder);
|
Image image = Image.of(name, imageKey, extension, folder);
|
||||||
imageRepository.save(image);
|
imageRepository.save(image);
|
||||||
}catch (Exception e){
|
} catch (Exception e) {
|
||||||
log.debug("이미지 DB 저장 실패: ", e);
|
log.debug("이미지 DB 저장 실패: ", e);
|
||||||
s3UploadService.deleteImageFromS3(imageKey);
|
s3UploadService.deleteImageFromS3(imageKey);
|
||||||
throw new CustomException(ErrorCode.FAIL_TO_CREATE_FILE);
|
throw new CustomException(ErrorCode.FAIL_TO_CREATE_FILE);
|
||||||
|
@ -40,7 +40,6 @@ import java.util.stream.Stream;
|
|||||||
|
|
||||||
@Slf4j
|
@Slf4j
|
||||||
@Service
|
@Service
|
||||||
@Transactional
|
|
||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
public class ImageService {
|
public class ImageService {
|
||||||
|
|
||||||
@ -56,9 +55,8 @@ public class ImageService {
|
|||||||
@CheckPrivilege(value = PrivilegeType.EDITOR)
|
@CheckPrivilege(value = PrivilegeType.EDITOR)
|
||||||
public void uploadImageList(final List<MultipartFile> imageList, final Integer folderId, final Integer projectId) {
|
public void uploadImageList(final List<MultipartFile> imageList, final Integer folderId, final Integer projectId) {
|
||||||
Folder folder = getOrCreateFolder(folderId, projectId);
|
Folder folder = getOrCreateFolder(folderId, projectId);
|
||||||
folderRepository.flush();
|
|
||||||
|
|
||||||
log.debug("folder Id {}, Project Id {}",folder.getId(), folder.getProject().getId());
|
log.debug("folder Id {}, Project Id {}", folder.getId(), folder.getProject().getId());
|
||||||
long prev = System.currentTimeMillis();
|
long prev = System.currentTimeMillis();
|
||||||
|
|
||||||
// 동적 배치 크기 계산
|
// 동적 배치 크기 계산
|
||||||
@ -78,7 +76,6 @@ public class ImageService {
|
|||||||
List<MultipartFile> batch = imageList.subList(i, Math.min(i + batchSize, imageList.size()));
|
List<MultipartFile> batch = imageList.subList(i, Math.min(i + batchSize, imageList.size()));
|
||||||
|
|
||||||
CompletableFuture<Void> future = imageAsyncService.asyncImageUpload(batch, folder, projectId);
|
CompletableFuture<Void> future = imageAsyncService.asyncImageUpload(batch, folder, projectId);
|
||||||
// 모든 비동기 작업이 완료될 때까지 기다림
|
|
||||||
futures.add(future);
|
futures.add(future);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -308,7 +305,8 @@ public class ImageService {
|
|||||||
String currentDateTime = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
|
String currentDateTime = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
|
||||||
Project project = getProject(projectId);
|
Project project = getProject(projectId);
|
||||||
Folder folder = Folder.of(currentDateTime, null, project);
|
Folder folder = Folder.of(currentDateTime, null, project);
|
||||||
folderRepository.save(folder); // 새로운 폴더를 저장
|
folderRepository.saveAndFlush(folder); // 새로운 폴더를 저장
|
||||||
|
|
||||||
return folder;
|
return folder;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package com.worlabel.domain.project.entity;
|
package com.worlabel.domain.project.entity;
|
||||||
|
|
||||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||||
|
import com.worlabel.domain.folder.entity.Folder;
|
||||||
import com.worlabel.domain.labelcategory.entity.ProjectCategory;
|
import com.worlabel.domain.labelcategory.entity.ProjectCategory;
|
||||||
import com.worlabel.domain.model.entity.AiModel;
|
import com.worlabel.domain.model.entity.AiModel;
|
||||||
import com.worlabel.domain.workspace.entity.Workspace;
|
import com.worlabel.domain.workspace.entity.Workspace;
|
||||||
@ -54,6 +55,12 @@ public class Project extends BaseEntity {
|
|||||||
@OneToMany(mappedBy = "project", fetch = FetchType.LAZY, cascade = CascadeType.ALL, orphanRemoval = true)
|
@OneToMany(mappedBy = "project", fetch = FetchType.LAZY, cascade = CascadeType.ALL, orphanRemoval = true)
|
||||||
private List<ProjectCategory> categoryList = new ArrayList<>();
|
private List<ProjectCategory> categoryList = new ArrayList<>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 프로젝트에 속한 폴더
|
||||||
|
*/
|
||||||
|
@OneToMany(mappedBy = "project", fetch = FetchType.LAZY, cascade = CascadeType.ALL, orphanRemoval = true)
|
||||||
|
private List<Folder> folderList = new ArrayList<>();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 프로젝트에 속한 모델
|
* 프로젝트에 속한 모델
|
||||||
*/
|
*/
|
||||||
@ -74,4 +81,8 @@ public class Project extends BaseEntity {
|
|||||||
this.title = title;
|
this.title = title;
|
||||||
this.projectType = projectType;
|
this.projectType = projectType;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void createFolder(final Folder folder) {
|
||||||
|
folderList.add(folder);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user