I/O와 트랜잭션 분리하기
퍼사드 패턴을 활용한 분리
장점
단점:
이벤트를 활용한 분리
장점
단점
Last updated
Last updated
@Service
@RequiredArgsConstructor
public class SearchBookUseCase {
private final KakaoApiClient kakaoApiClient;
public SearchBookResponse search(String query, String sort, int size, int page, String target) {
return SearchBookResponse.from(kakaoApiClient.searchBooks(query, sort, page, size, target));
}
}@Service
@RequiredArgsConstructor
public class SearchBookUseCase {
private final KakaoApiClient kakaoApiClient;
private final BookCountRepository bookCountRepository;
@Transactional
public SearchBookResponse search(String query, String sort, int size, int page, String target) {
bookCountRepository.findByQuery(query)
.ifPresentOrElse(
bookCount -> bookCountRepository.updateCount(bookCount.getId(), bookCount.getCount() + 1),
() -> bookCountRepository.save(new BookCount(query, 1))
);
return SearchBookResponse.from(kakaoApiClient.searchBooks(query, sort, page, size, target));
}
}@Service
@RequiredArgsConstructor
public class SearchCountService {
private final BookCountRepository bookCountRepository;
@Transactional
public void incrementSearchCount(String query) {
bookCountRepository.findByQuery(query)
.ifPresentOrElse(
bookCount -> bookCountRepository.updateCount(bookCount.getId(), bookCount.getCount() + 1),
() -> bookCountRepository.save(new BookCount(query, 1))
);
}
}@Service
@RequiredArgsConstructor
public class SearchBookFacade {
private final KakaoApiClient kakaoApiClient;
private final SearchCountService searchCountService;
public SearchBookResponse search(String query, String sort, int size, int page, String target) {
// 외부 API 호출 먼저 수행
SearchBookResponse response = SearchBookResponse.from(
kakaoApiClient.searchBooks(query, sort, page, size, target)
);
// DB 작업은 별도로 수행
searchCountService.incrementSearchCount(query);
return response;
}
}@Component
@RequiredArgsConstructor
public class SearchCountEventListener {
private final SearchCountService searchCountService;
@TransactionalEventListener(phase = TransactionPhase.AFTER_COMMIT)
public void handleSearchEvent(SearchPerformedEvent event) {
searchCountService.incrementSearchCount(event.getQuery());
}
}@Service
@RequiredArgsConstructor
public class SearchBookService {
private final KakaoApiClient kakaoApiClient;
private final ApplicationEventPublisher eventPublisher;
public SearchBookResponse search(String query, String sort, int size, int page, String target) {
SearchBookResponse response = SearchBookResponse.from(
kakaoApiClient.searchBooks(query, sort, page, size, target)
);
// 이벤트 발행
eventPublisher.publishEvent(new SearchPerformedEvent(query));
return response;
}
}