전체 글
exists 메서드 성능 개선 - count vs exists
2월 중순에 마무리 되었던 프로젝트에 대해 리팩토링을 진행하고자 코드를 찬찬히 훑던 중, QueryDsl로 exists 관련 메서드를 구현한 부분에서 개선점이 발견되어 성능을 개선해보았다. 일반적으로 많이 사용하는 방식이자 QueryDsl에서 구현되어있는 방식인 exists 메서드의 성능 측면 문제점을 먼저 비교해보고, 개선한 방식에 대해서 설명한다. 일반적인 exists 관련 쿼리는 아래와 같이 구현한다. select exists( select 1 from member where age = 1); exists 내 서브쿼리를 통해 조건에 해당하는 컬럼이 존재하는지를 반환하는 형태의 쿼리를 이용한다. 스프링 내에서 JpaRepository를 이용해 간단한 조건에 대한 exists 메서드는 다음과 같이 Na..
Jsoup 라이브러리를 통한 정적 페이지 크롤링
- 발생한 문제 1. 카카오 Local API를 사용하여 키워드를 통한 장소 검색을 구현. 2. 이 때, 장소에 해당하는 대표 이미지를 함께 보내주어야 하는데, 카카오 Local API의 장소 Response에는 대표 이미지가 없음. - 시도한 방법 1 (실패) : OpenGraph OpenGraph란, HTML 문서에 대해서 다양한 메타데이터를 통일성있게 제공할 수 있도록 Facebook에서 만든 프로토콜이다. HTML 문서의 meta 태그 중 "og:" prefix로 시작하는 부분이 OpenGraph 프로토콜 관련 메타데이터이다. 이 OpenGraph의 경우, url에 해당하는 메타데이터로 title(제목), url, image(썸네일 이미지)를 포함하고 있다. 예를 들어, 네이버의 경우 HTML ..
order by 조건 설정 - 현재 기준 n일 미만 내 작성된 게시글 상위에 정렬
- 구현해야 하는 조건 : Request Parameter의 sortBy 값에 따라 0일 경우 작성일 기준 최신순 정렬 / 1일 경우 인기순으로 정렬하되, 현재 날짜 기준 일주일 미만의 게시글은 상위에, 일주일 이후의 게시글은 하위에 우선적으로 정렬한다. 위 조건에 따라서, 기본적인 JPA 기능만으로는 동적 쿼리를 작성하기 힘들다고 판단해 QueryDSL을 통해 구현하였다. sortBy = 0일 경우 작성일 기준 최신순 정렬에 해당하는 로직은 작성일 기준 내림차순 정렬만 수행하면 쉽게 구현할 수 있다. 그러나 sortBy=1일 경우 현재 날짜를 기준으로 7일 미만의 게시글을 상위, 이후 게시글은 하위에 정렬해야 하는 부분에서 어려움이 있었다. 최초에 구상해 본 QueryDSL의 orderBy 로직은 아래..
Entity Class에 Lombok @NoArgsConstructor(access=PROTECTED)를 붙이는 이유
코드를 작성하면서 습관적으로 Entity Class에 @NoArgsConstructor(access = AccessLevel.PROTECTED) Lombok 어노테이션을 붙여왔다. 이번에 아래 내용에 대해 명확하게 정리하고자 한다. 0. Lombok의 @NoArgsConstructor 어노테이션이란 1. JPA의 Entity Class에 @NoArgsConstructor (기본 생성자) 가 필요한 이유 2. JPA의 Entity Class에서 기본 생성자의 access level을 Public 또는 Protected로 제한하는 이유 3. @NoArgsConstructor의 access level을 Protected로 제한하였을 때의 장점 0. Lombok의 @NoArgsConstructor 어노테이션이란..
Proxy로 생성되는 Service와 의존관계를 갖는 @Repository, JpaRepository는 Proxy일까?
의문점 : class level 또는 method level에 @Transactional 어노테이션이 붙어있는 Service 클래스는 Transaction 관련 코드(트랜잭션 시작, 커밋 또는 롤백, 트랜잭션 종료)가 추가된 Proxy 객체를 Bean으로 등록해 Transaction 기능을 수행한다. 그렇다면 아래와 같이 Service 내에 DI 컨테이너에서 주입받은 두가지 방식의 Repository는 Proxy일까? Proxy라면 무슨 부가기능을 위해 Proxy가 된 것일까? 1. Spring Framework의 @Repository 2. Spring Data Jpa의 JpaRepository // Proxy 객체로 DI 컨테이너에 등록되는 Service class @Service @Transactio..
fetch join + Paging (limit) 처리 시 발생하는 문제 및 해결
발생 문제 : JPA를 통해 아래와 같은 연관관계를 갖는 엔티티를 조회 할 때, fetch join과 Paging을 함께 사용하여 조회 시 fetch join이 적용되지 않고 DB를 Full Scan하여 페이징을 적용하는 상황이 발생한다. 다음과 같이 하나의 Review에 대해 N개의 Image를 가지는 1:N 연관관계로 구성되어 있다. Paging을 사용하여 10개의 Review를 연관된 Image Entity와 함께 fetch join으로 가져오고자 다음과 같은 쿼리를 작성하였다. // ReviewRepository.class @Query("select r from Review r " + "join r.company c " + "fetch join r.images i " + // LAZY fetch에..
JWT를 사용한 로그인 및 Refresh Token을 활용한 로그인 상태 유지
구현 내용 : 1. Spring Security + JWT를 사용해 username, password를 통해 로그인 완료 시 Access Token 및 Refresh Token 발급 2. Access Token 만료 시 Refresh Token을 통한 Access Token 재발급 (로그인 상태 유지) 2-1. Refresh Token의 갱신 주기 도달 시 Refresh Token도 함께 재발급 (로그인 유지 기간 연장) 3. Access Token + Refresh Token 만료 시 Error Response를 통한 인증 만료 처리 설계 및 Response : - AT : Access Token / 만료기간 : 12시간 - RT : Refresh Token / 만료기간 : 3개월 / refresh..
[Effective Java] Item20. 추상 클래스보다는 인터페이스를 우선하라
Item20. 추상 클래스보다는 인터페이스를 우선하라 자바는 단일 상속, 다중 구현 메커니즘을 가진다. 즉, 클래스는 하나만 상속할 수 있지만 인터페이스는 여러 개를 구현할 수 있다. ! 클래스, 인터페이스의 차이 클래스 : 추상 클래스를 상속받는 클래스는 반드시 추상 클래스의 하위 클래스가 된다. 인터페이스 : 어떤 클래스를 상속하든 하위 타입이 아닌 같은 타입으로 취급된다. ! 인터페이스는 믹스인(mixin) 정의에 안성맞춤이다 기존 클래스에 손쉽게 인터페이스를 구현할 수 있다. 반면, 기존 클래스에 추상 클래스를 끼워 넣기는 어렵다. 계층구조상 상위하위의 구조를 가지므로 클래스 계층구조에 혼란을 야기한다. 이러한 이유로, 인터페이스는 *믹스인(mixin) 정의에 안성맞춤이다. *믹스인(mixin) ..
[Effective Java] Item06. 불필요한 객체 생성을 피하라
Item06. 불필요한 객체 생성을 피하라 같은 기능을 수행하는 객체를 매번 생성하는 것보다 하나를 재사용하는 편이 나을 때가 많다. 특히, 불변 객체는 언제든 재사용 할 수 있다. ! 객체의 재사용에 대한 극단적인 예 로 String type을 들 수 있다. // 실행될 때마다 새로운 String 인스턴스가 생성됨 String s = new String("hunseong"); // String Constant Pool 영역에서 해당 리터럴을 찾음 // 리터럴이 존재한다면 재사용, 없다면 해당 영역에 리터럴 추가 String s = "hunseong"; ! 정적 팩터리 메서드를 제공하는 불변 클래스에서는 정적 팩터리 메서드를 사용해 불필요한 객체 생성을 피할 수 있다. // 생성자 - 매번 새로운 인..
[Effective Java] Item03. private 생성자나 열거 타입으로 싱글턴임을 보증하라
Item03. private 생성자나 열거 타입으로 싱글턴임을 보증하라 싱글턴(singleton) : 인스턴스를 오직 하나만 생성할 수 있는 클래스. 보통 무상태(stateless) 객체나 설계상 유일해야 하는 시스템 컴포넌트 등에 사용. ! public static final 필드 방식의 싱글턴 - 생성자를 private으로 설정하여 외부에서 인스턴스를 생성할 수 없게 한다. - public static final 필드로 new 키워드를 통해 인스턴스를 하나만 생성한다. - 외부에서는 SingletonClass.INSTANCE를 통해 인스턴스에 접근한다. public class Singleton1 { // public static 멤버 변수를 통해 싱글턴 인스턴스 생성 public static fina..