Skip to content

Commit

Permalink
쿼리 분석 및 성능개선 (#87)
Browse files Browse the repository at this point in the history
* fix: session 가져오는 로직 변경 및 Long에서 MemberId 반환하도록 변경

- 기존 Long으로 사용시 AuthArgumentResolver가 동작안하고 기본 argumentresolver가 동작

* refactor: 리뷰 내용 없을 경우 예외 반환

* refactor: session 없을 시, 예외 던지도록 변경

* fix: 시간정보 null일 때 처리

* feat: 인덱스 적용

- 주차장 공간 인덱스 적용
- 조회 조건에서 회원 id에 인덱스 적용
- 리뷰에서 주차장 id, 리뷰 id 복합 인덱스 적용

* refactor: 인터셉터에서 사용하는 세션 쿼리 개선

- readOnly 트랜잭션으로 읽어오고 만료기한 update를 위해 조회 추가 쿼리 발생(총 3회)에서 2회로 개선

* fix: CircuitBreaker 테스트 시간 조정

* fix: 세션 쿼리 테스트 커밋 안된 부분 커밋
  • Loading branch information
This2sho authored Jun 15, 2024
1 parent a138079 commit 8fd8343
Show file tree
Hide file tree
Showing 28 changed files with 153 additions and 93 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import com.parkingcomestrue.parking.application.favorite.FavoriteService;
import com.parkingcomestrue.parking.application.favorite.dto.FavoriteCreateRequest;
import com.parkingcomestrue.parking.application.favorite.dto.FavoriteDeleteRequest;
import com.parkingcomestrue.parking.application.member.dto.MemberId;
import com.parkingcomestrue.parking.config.argumentresolver.MemberAuth;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
Expand All @@ -25,15 +26,15 @@ public class FavoriteController {
@Operation(summary = "즐겨찾기 등록", description = "즐겨찾기 등록")
@PostMapping("/favorites")
public ResponseEntity<Void> create(@RequestBody FavoriteCreateRequest favoriteCreateRequest,
@Parameter(hidden = true) @MemberAuth Long memberId) {
@Parameter(hidden = true) @MemberAuth MemberId memberId) {
favoriteService.createFavorite(favoriteCreateRequest, memberId);
return ResponseEntity.status(HttpStatus.CREATED).build();
}

@Operation(summary = "즐겨찾기 해제", description = "즐겨찾기 해제")
@DeleteMapping("/favorites")
public ResponseEntity<Void> delete(@RequestBody FavoriteDeleteRequest favoriteDeleteRequest,
@Parameter(hidden = true) @MemberAuth Long memberId) {
@Parameter(hidden = true) @MemberAuth MemberId memberId) {
favoriteService.deleteFavorite(favoriteDeleteRequest, memberId);
return ResponseEntity.status(HttpStatus.NO_CONTENT).build();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import com.parkingcomestrue.parking.application.auth.AuthService;
import com.parkingcomestrue.parking.application.member.MemberService;
import com.parkingcomestrue.parking.application.member.dto.MemberId;
import com.parkingcomestrue.parking.application.member.dto.MemberLoginRequest;
import com.parkingcomestrue.parking.application.member.dto.MemberSignupRequest;
import com.parkingcomestrue.parking.application.member.dto.PasswordChangeRequest;
Expand Down Expand Up @@ -49,9 +50,9 @@ public ResponseEntity<Void> signIn(HttpServletResponse httpServletResponse,

@Operation(summary = "비밀번호 변경", description = "비밀번호 변경")
@PatchMapping("/member/password")
public ResponseEntity<Void> changePassword(@Parameter(hidden = true) @MemberAuth Long memberId,
public ResponseEntity<Void> changePassword(@Parameter(hidden = true) @MemberAuth MemberId memberId,
@RequestBody PasswordChangeRequest request) {
memberService.changePassword(memberId, request);
memberService.changePassword(memberId.getId(), request);
return ResponseEntity.status(HttpStatus.NO_CONTENT).build();
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.parkingcomestrue.parking.api.parking;

import com.parkingcomestrue.parking.application.member.dto.MemberId;
import com.parkingcomestrue.parking.application.parking.ParkingService;
import com.parkingcomestrue.parking.application.parking.dto.ParkingDetailInfoResponse;
import com.parkingcomestrue.parking.application.parking.dto.ParkingLotsResponse;
Expand Down Expand Up @@ -30,15 +31,14 @@ public class ParkingController {
public ResponseEntity<ParkingDetailInfoResponse> findParking(@PathVariable Long parkingId) {
ParkingDetailInfoResponse parkingDetailInfoResponse = parkingService.findParking(parkingId);
return ResponseEntity.status(HttpStatus.OK).body(parkingDetailInfoResponse);

}

@Operation(summary = "주차장 반경 조회", description = "주차장 반경 조회")
@GetMapping("/parkings")
public ResponseEntity<ParkingLotsResponse> find(
@ParkingQuery ParkingQueryRequest parkingQueryRequest,
@ParkingSearchCondition ParkingSearchConditionRequest parkingSearchConditionRequest,
@Parameter(hidden = true) @MemberAuth(nullable = true) Long parkingMemberId
@Parameter(hidden = true) @MemberAuth(nullable = true) MemberId parkingMemberId
) {
ParkingLotsResponse parkingLots = parkingService.findParkingLots(parkingQueryRequest,
parkingSearchConditionRequest, parkingMemberId);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.parkingcomestrue.parking.api.review;

import com.parkingcomestrue.parking.application.member.dto.MemberId;
import com.parkingcomestrue.parking.application.review.ReviewService;
import com.parkingcomestrue.parking.application.review.dto.ReviewCreateRequest;
import com.parkingcomestrue.parking.config.argumentresolver.MemberAuth;
Expand All @@ -8,6 +9,7 @@
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PathVariable;
Expand All @@ -22,9 +24,9 @@ public class ReviewController {
private final ReviewService reviewService;

@Operation(summary = "리뷰 등록", description = "리뷰 등록")
@PostMapping("/parkings/{parkingId}/reviews")
@PostMapping(value = "/parkings/{parkingId}/reviews", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
public ResponseEntity<Long> createReview(@PathVariable Long parkingId,
@Parameter(hidden = true) @MemberAuth Long memberId,
@Parameter(hidden = true) @MemberAuth MemberId memberId,
@ModelAttribute ReviewCreateRequest request) {
Long reviewId = reviewService.createReview(parkingId, memberId, request);
return ResponseEntity.status(HttpStatus.CREATED).body(reviewId);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,36 +1,36 @@
package com.parkingcomestrue.parking.api.searchcondition;

import com.parkingcomestrue.parking.application.member.dto.MemberId;
import com.parkingcomestrue.parking.application.searchcondition.SearchConditionService;
import com.parkingcomestrue.parking.application.searchcondition.dto.SearchConditionDto;
import com.parkingcomestrue.parking.config.argumentresolver.MemberAuth;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RestController;

@Tag(name = "조회 조건 컨트롤러")
@RequiredArgsConstructor
@RestController
public class SearchConditionController {

private final SearchConditionService searchConditionService;

public SearchConditionController(SearchConditionService searchConditionService) {
this.searchConditionService = searchConditionService;
}

@Operation(summary = "조회 조건 조회", description = "조회 조건 조회")
@GetMapping("/search-condition")
public ResponseEntity<SearchConditionDto> loadSearchCondition(@Parameter(hidden = true) @MemberAuth Long memberId) {
public ResponseEntity<SearchConditionDto> loadSearchCondition(
@Parameter(hidden = true) @MemberAuth MemberId memberId) {
return ResponseEntity.ok(searchConditionService.findSearchCondition(memberId));
}

@Operation(summary = "조회 조건 수정", description = "조회 조건 수정")
@PutMapping("/search-condition")
public ResponseEntity<Void> updateSearchCondition(@Parameter(hidden = true) @MemberAuth Long memberId,
public ResponseEntity<Void> updateSearchCondition(@Parameter(hidden = true) @MemberAuth MemberId memberId,
SearchConditionDto request) {
searchConditionService.updateSearchCondition(memberId, request);
return ResponseEntity.status(HttpStatus.CREATED).build();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,19 +48,20 @@ public String createSession(Long memberId) {
return memberSession.getSessionId();
}

@Transactional
public void findAndUpdateSession(String sessionId) {
MemberSession session = findSession(sessionId);
session.updateExpiredAt(LocalDateTime.now().plusMinutes(DURATION_MINUTE));
memberSessionRepository.save(session);
}

@Transactional(readOnly = true)
public MemberSession findSession(String sessionId) {
return memberSessionRepository.findBySessionIdAndExpiredAtIsGreaterThanEqual(sessionId,
LocalDateTime.now())
.orElseThrow(() -> new ClientException(ClientExceptionInformation.UNAUTHORIZED));
}

@Transactional
public void updateSessionExpiredAt(MemberSession session) {
session.updateExpiredAt(LocalDateTime.now().plusMinutes(DURATION_MINUTE));
memberSessionRepository.save(session);
}

@Transactional
public String createAuthCode(AuthCodeRequest authCodeRequest) {
String destination = authCodeRequest.getDestination();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
package com.parkingcomestrue.parking.application.favorite;

import com.parkingcomestrue.parking.application.favorite.dto.FavoriteCreateRequest;
import com.parkingcomestrue.parking.application.favorite.dto.FavoriteDeleteRequest;
import com.parkingcomestrue.common.domain.favorite.Favorite;
import com.parkingcomestrue.common.domain.favorite.repository.FavoriteRepository;
import com.parkingcomestrue.common.support.Association;
import com.parkingcomestrue.parking.application.favorite.dto.FavoriteCreateRequest;
import com.parkingcomestrue.parking.application.favorite.dto.FavoriteDeleteRequest;
import com.parkingcomestrue.parking.application.member.dto.MemberId;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.dao.DataIntegrityViolationException;
Expand All @@ -19,10 +20,10 @@ public class FavoriteService {

private final FavoriteRepository favoriteRepository;

public void createFavorite(FavoriteCreateRequest favoriteCreateRequest, Long memberId) {
public void createFavorite(FavoriteCreateRequest favoriteCreateRequest, MemberId memberId) {
Long parkingId = favoriteCreateRequest.getParkingId();

Favorite favorite = new Favorite(Association.from(memberId), Association.from(parkingId));
Favorite favorite = new Favorite(Association.from(memberId.getId()), Association.from(parkingId));
saveFavorite(favorite);
}

Expand All @@ -35,9 +36,10 @@ private void saveFavorite(Favorite favorite) {
}
}

public void deleteFavorite(FavoriteDeleteRequest favoriteDeleteRequest, Long memberId) {
public void deleteFavorite(FavoriteDeleteRequest favoriteDeleteRequest, MemberId memberId) {
Long parkingId = favoriteDeleteRequest.getParkingId();

favoriteRepository.deleteByMemberIdAndParkingId(Association.from(memberId), Association.from(parkingId));
favoriteRepository.deleteByMemberIdAndParkingId(Association.from(memberId.getId()),
Association.from(parkingId));
}
}
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
package com.parkingcomestrue.parking.application.member;

import com.parkingcomestrue.common.domain.member.Member;
import com.parkingcomestrue.common.domain.member.Password;
import com.parkingcomestrue.common.domain.member.repository.MemberRepository;
import com.parkingcomestrue.parking.application.member.dto.MemberInfoResponse;
import com.parkingcomestrue.parking.application.member.dto.MemberLoginRequest;
import com.parkingcomestrue.parking.application.member.dto.MemberSignupRequest;
import com.parkingcomestrue.parking.application.member.dto.PasswordChangeRequest;
import com.parkingcomestrue.common.domain.member.Member;
import com.parkingcomestrue.common.domain.member.repository.MemberRepository;
import com.parkingcomestrue.common.domain.member.Password;
import com.parkingcomestrue.parking.support.exception.ClientException;
import com.parkingcomestrue.parking.support.exception.ClientExceptionInformation;
import org.springframework.stereotype.Service;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package com.parkingcomestrue.parking.application.member.dto;

import lombok.Getter;

@Getter
public class MemberId {

private long id;

private MemberId(long id) {
this.id = id;
}

public static MemberId from(long id) {
return new MemberId(id);
}

public boolean isGuestUser() {
return id < 0;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,13 @@
import com.parkingcomestrue.common.domain.parking.ParkingFeeCalculator;
import com.parkingcomestrue.common.domain.parking.ParkingType;
import com.parkingcomestrue.common.domain.parking.PayType;
import com.parkingcomestrue.common.domain.parking.service.SearchingCondition;
import com.parkingcomestrue.common.domain.parking.repository.ParkingRepository;
import com.parkingcomestrue.common.domain.parking.service.ParkingFilteringService;
import com.parkingcomestrue.common.domain.parking.service.SearchingCondition;
import com.parkingcomestrue.common.domain.searchcondition.FeeType;
import com.parkingcomestrue.common.support.Association;
import com.parkingcomestrue.parking.application.SearchConditionMapper;
import com.parkingcomestrue.parking.application.member.dto.MemberId;
import com.parkingcomestrue.parking.application.parking.dto.ParkingDetailInfoResponse;
import com.parkingcomestrue.parking.application.parking.dto.ParkingDetailInfoResponse.FeeInfo;
import com.parkingcomestrue.parking.application.parking.dto.ParkingDetailInfoResponse.HolidayOperatingTime;
Expand Down Expand Up @@ -51,7 +52,7 @@ public class ParkingService {
@Transactional(readOnly = true)
public ParkingLotsResponse findParkingLots(ParkingQueryRequest parkingQueryRequest,
ParkingSearchConditionRequest parkingSearchConditionRequest,
Long memberId) {
MemberId memberId) {
LocalDateTime now = LocalDateTime.now();
Location destination = Location.of(parkingQueryRequest.getLongitude(), parkingQueryRequest.getLatitude());

Expand All @@ -72,11 +73,11 @@ public ParkingLotsResponse findParkingLots(ParkingQueryRequest parkingQueryReque
return new ParkingLotsResponse(parkingResponses);
}

private List<Favorite> findMemberFavorites(Long memberId) {
if (memberId == null) {
private List<Favorite> findMemberFavorites(MemberId memberId) {
if (memberId.isGuestUser()) {
return Collections.emptyList();
}
return favoriteRepository.findByMemberId(Association.from(memberId));
return favoriteRepository.findByMemberId(Association.from(memberId.getId()));
}

private List<Parking> findParkingLotsByOrderCondition(String priority, ParkingQueryRequest parkingQueryRequest,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.parkingcomestrue.parking.application.review;

import com.parkingcomestrue.parking.application.member.dto.MemberId;
import com.parkingcomestrue.parking.application.review.dto.ReviewCountResponse;
import com.parkingcomestrue.parking.application.review.dto.ReviewCreateRequest;
import com.parkingcomestrue.parking.application.review.dto.ReviewInfoResponse;
Expand All @@ -24,10 +25,10 @@ public class ReviewService {
private final ReviewDomainService reviewDomainService;

@Transactional
public Long createReview(Long parkingId, Long reviewerId, ReviewCreateRequest request) {
reviewDomainService.validateDuplicateReview(Association.from(parkingId), Association.from(reviewerId));
public Long createReview(Long parkingId, MemberId reviewerId, ReviewCreateRequest request) {
reviewDomainService.validateDuplicateReview(Association.from(parkingId), Association.from(reviewerId.getId()));

Review review = new Review(Association.from(parkingId), Association.from(reviewerId), request.toContents());
Review review = new Review(Association.from(parkingId), Association.from(reviewerId.getId()), request.toContents());
reviewRepository.save(review);
return review.getId();
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,18 @@
package com.parkingcomestrue.parking.application.review.dto;

import com.parkingcomestrue.common.domain.review.Content;
import com.parkingcomestrue.common.support.exception.DomainException;
import com.parkingcomestrue.common.support.exception.DomainExceptionInformation;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

public record ReviewCreateRequest(List<String> contents) {

public Set<Content> toContents() {
if (contents == null) {
throw new DomainException(DomainExceptionInformation.INVALID_CONTENT);
}
return contents.stream()
.map(Content::find)
.collect(Collectors.toSet());
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package com.parkingcomestrue.parking.application.searchcondition;

import com.parkingcomestrue.common.domain.member.Member;
import com.parkingcomestrue.parking.application.SearchConditionMapper;
import com.parkingcomestrue.parking.application.member.dto.MemberId;
import com.parkingcomestrue.parking.application.searchcondition.dto.SearchConditionDto;
import com.parkingcomestrue.common.domain.parking.OperationType;
import com.parkingcomestrue.common.domain.parking.ParkingType;
Expand All @@ -26,8 +28,8 @@ public class SearchConditionService {
private final SearchConditionRepository searchConditionRepository;
private final SearchConditionMapper searchConditionMapper;

public SearchConditionDto findSearchCondition(Long memberId) {
SearchCondition searchCondition = searchConditionRepository.getByMemberId(memberId);
public SearchConditionDto findSearchCondition(MemberId memberId) {
SearchCondition searchCondition = searchConditionRepository.getByMemberId(Association.from(memberId.getId()));
return toSearchConditionDto(searchCondition);
}

Expand All @@ -50,18 +52,18 @@ private <E extends SearchConditionAvailable> List<String> toDescriptions(Set<E>
}

@Transactional
public void updateSearchCondition(Long memberId, SearchConditionDto searchConditionDto) {
SearchCondition newSearchCondition = createSearchCondition(memberId, searchConditionDto);
public void updateSearchCondition(MemberId memberId, SearchConditionDto searchConditionDto) {
SearchCondition newSearchCondition = createSearchCondition(Association.from(memberId.getId()), searchConditionDto);

searchConditionRepository.findByMemberId(memberId).ifPresentOrElse(
searchConditionRepository.findByMemberId(Association.from(memberId.getId())).ifPresentOrElse(
existingSearchCondition -> existingSearchCondition.update(newSearchCondition),
() -> searchConditionRepository.save(newSearchCondition)
);
}

private SearchCondition createSearchCondition(Long memberId, SearchConditionDto searchConditionDto) {
private SearchCondition createSearchCondition(Association<Member> memberId, SearchConditionDto searchConditionDto) {
return new SearchCondition(
Association.from(memberId),
memberId,
searchConditionMapper.toEnums(OperationType.class, searchConditionDto.getOperationType()),
searchConditionMapper.toEnums(ParkingType.class, searchConditionDto.getParkingType()),
searchConditionMapper.toEnums(FeeType.class, searchConditionDto.getFeeType()),
Expand Down
Loading

0 comments on commit 8fd8343

Please sign in to comment.