기존 UserRepositoryQueryImpl.java 이용해 검색했을 때
@Component
@RequiredArgsConstructor
public class UserRepositoryQueryImpl implements UserRepositoryQuery {
private final JPAQueryFactory jpaQueryFactory;
@Override
public List<User> searchUserByKeyword(UserSearchCond cond) {
return searchByKeyword(cond, user.username);
}
@Override
public List<User> searchNickByKeyword(UserSearchCond cond) {
return searchByKeyword(cond, user.nickname);
}
private List<User> searchByKeyword(UserSearchCond cond, StringPath field) {
var query = jpaQueryFactory.selectFrom(user)
.where(containsKeyword(field, cond.getKeyword()));
query.setHint(AvailableHints.HINT_READ_ONLY, true);
return query.fetch();
}
private BooleanExpression containsKeyword(StringPath field, String keyword) {
return StringUtils.hasText(keyword) ? field.containsIgnoreCase(keyword) : null;
}
}
Jpa 쿼리 메서드를 이용해 검색했을 때
UserService.java
@Transactional(readOnly = true)
public SearchUserResponseDto searchUserByKeyword(UserSearchCond userSearchCond) {
List<User> u1 = userRepository.findAllByUsernameContaining(userSearchCond.getKeyword());
List<User> u2 = userRepository.findAllByNicknameContaining(userSearchCond.getKeyword());
List<SimpleUserInfoDto> result = mergeUserResultLists(u1, u2)
.stream()
.map(SimpleUserInfoDto::new)
.toList();
return new SearchUserResponseDto(result);
}
기존 코드는 QueryDSL을 사용하지 않아도 된다.
(간단한 검색이고 동적인 쿼리를 만들 필요가 없기 때문)
오히려 Jpa 쿼리 메서드를 사용하는 쪽이 빠르다.
UserRepositoryQueryImpl.java
@Component
@RequiredArgsConstructor
public class UserRepositoryQueryImpl implements UserRepositoryQuery {
private final JPAQueryFactory jpaQueryFactory;
@Override
public List<User> search(UserSearchCond cond) {
var query = jpaQueryFactory.selectFrom(user)
.where(
Objects.requireNonNull(containsKeyword(user.username, cond.getKeyword()))
.or(containsKeyword(user.nickname, cond.getKeyword()))
);
query.setHint(AvailableHints.HINT_READ_ONLY, true);
return query.fetch();
}
private BooleanExpression containsKeyword(StringPath field, String keyword) {
return StringUtils.hasText(keyword) ? field.containsIgnoreCase(keyword) : null;
}
}
훨씬 빠르게 동작하는 것을 확인할 수 있다.
UserProfile.java
필요한 정보만 담을 dto
@Component
@NoArgsConstructor
@Getter
public class UserProfile {
private Long userId;
private String username;
private String nickname;
public UserProfile(Long id, String username, String nickname) {
this.userId = id;
this.username = username;
this.nickname = nickname;
}
}
더 빠르게 동작하는 것을 확인할 수 있다.
사용자를 검색하는 경우는 채팅방에 초대할 때 뿐이므로 다른 정보를 조회하지 않는 편이 낫다고 판단해 위와 같이 수정했다.