JAVA Spring에서 RDB를 사용하면서 많은 연관 관계를 최소한의 Query로 DB를 조회함과 동시에 JAVA의 객체 지향을 살릴 수 있는 방법들을 고민해보고 방법들을 기록으로 남긴다.
Order doneOrder = message.buildOrder(user,
vacationRepository.getReferenceById(message.getMarketId()),
sellingOrderAmount,
OrderStatus.DONE
);
findById 나 QueryDSL의 selectFrom 은 불필요한 많은 데이터 입출력이 이루어지게 된다.select 구문으로 가져오고 싶다.Projections.field
public List<LatestCahootsDto> findLatestVacations(){
return queryFactory
.select(Projections.fields(LatestCahootsDto.class,
vacation.id,
vacation.title,
vacation.stockPeriod.start.as("stockStart"),
vacation.expectedRateOfReturn))
.from(vacation)
.where(isInStatus(new VacationStatusType[]{VacationStatusType.CAHOOTS_ONGOING}), isInStartDateRange(recentDays))
.orderBy(vacation.stockPeriod.start.desc())
.limit(this.page)
.fetch();
}
Projections.constructor
@QueryProjection Annotation 사용하기
먼저 DTO 정의하기
우리가 만약 TransactionResponseDto 를 사용하였다고 가정하면 해당 생성자에다가 @QueryProjection을 설정하면 된다.
@QueryProjection
public TransactionResponseDto(LocalDateTime date, Integer price, Integer amount) {
this.date = date;
this.price = price;
this.amount = amount;
}
repositoryimpl에 사용하기
여기서는 우리가 DTO 에서 정의한 생성자를 기반으로 QDTO라고 이름을 붙여 사용할 수 있다.
@Override
public List<TransactionResponseDto> findByVacationOrderByCreatedAtDesc(Pageable page, TransactionRequestDto requestDto) {
DateTemplate<LocalDateTime> formattedDate = Expressions.dateTemplate(LocalDateTime.class, "DATE_FORMAT({0}, {1})", transaction.createdAt, "%Y-%m-%d");
DateTemplate<LocalDateTime> beforeDate = convertIntoDateTemplate(requestDto.getStartDate());
DateTemplate<LocalDateTime> afterDate = convertIntoDateTemplate(requestDto.getEndDate());
return jpqlQueryFactory
.select(new QTransactionResponseDto(transaction.createdAt, transaction.price, transaction.amount))
.from(transaction)
.where(
transaction.vacation.id.eq(requestDto.getVacationId())
.and(formattedDate.between(beforeDate, afterDate))
)
.offset(page.getOffset())
.limit(page.getPageSize())
.orderBy(transaction.createdAt.desc())
.fetch();
}
상황 : 공모 신청 시 여러 개의 이미지 데이터가 전달되어오면, 하나 씩 S3에 올리고 url을 저장하면 repository.save를 여러 번 호출해야한다.
고민 : Array로 url들을 모아뒀다가 한번에 repository에 저장 요청을 하고싶다.
해결 : repository.saveAll()
더 나은 이유 : save 함수 한 번당 트랜잭션 Proxy 로직을 태웁니다.
→ 그렇기 때문에, 기존 트랜잭션이 있는 경우 해당 트랜잭션에 참여하게 되지만, 이러한 경우에도 어느정도 비용이 발생합니다.
→ 그래서, 다 건 조회 시 매번마다 위 비용이 발생하기 때문에 시간이 오래 걸립니다.
반면, saveAll 함수 전체에 하나의 트랜잭션이 존재하고, save는 내부 메소드 호출로 트랜잭션 Proxy 로직을 태우지 않습니다.
→ 그렇기 때문에, 트랜잭션 관련 비용이 발생하지 않습니다.
→ 그래서, 다 건 조회 시에 적합합니다.
public void saveFiles(List<MultipartFile> images, String type) {
List<Picture> imageUrls = this.getUrlsFromS3(images, type);
pictureRepository.saveAll(imageUrls);
}