본문 바로가기
카테고리 없음

[기록] 220209

by 공부중중 2022. 2. 13.

1. WAS란

1)Web Server
-SW : 정적인 페이지(html, jpg 등)을 표현하기 위한 서버로 클라이언트의 요청에 따른 응답을 해주는 역할을 수행

2)Web Application Server (WAS)
-미들웨어 소프트웨어
-웹브라우져의 요청(url)을 받아 웹 애플리케이션(CGI)를 호출하여 실행결과를 클라이언트에 보내주는 역할을 담당함
-트랜잭션 처리, 쓰래드 관리, 동시성, 보안, DB(connection pool 등), 비용절감 등을 지원
-CGI -> Servlet -> JSP, ASP, php 등으로 발전

3)WAS, WebServer
*종류
Was Server : tomcat, tMax jeus, BEA Web Logic, IBM Web Spere, JBOSS, Bluestone, Gemston, Inprise, Oracle, PowerTier, Apptivity, SilverStream
Web Server : IIS, apache, tMax WebtoB

4)WAS 기술 표준
J2EE : Java 기반의 분산객체 아키텍쳐, 쉽게 말해서 JAVA에 관련된 모듈의 표준규약
(was => jsp/servlet, db => jdbc 등)
WAS는 J2EE 아키텍쳐를 구현한 플랫폼 솔루션( = JSP/Servlet으로 구현되었다)
WAS의 일반적인 기능, Web 환경을 위한 n-tier Architecture 플랫폼

5)다양한 WAS Framework

EJB (Entertainment JAVA BEAN)
-분산환경을 지원하기 위한 J2EE기술
-EJB 컨테이너의 다양한 기능지원 : 객체관리, 트랜잭션, 보안, 데이터베이스 등
-다양한 기능으로 인한 퍼포먼스 저하
-대형 기업 어플리케이션 시장, 금융권에서 사용됨

Spring framework
-로드 존슨이 만든기법
-EJB서버와 같은 거창한 컨테이너가 필요없다
-오픈소스 프레임웍이라서 사용이 무료
-각종 기업용 어플리케이션 개발에 필요한 상당히 많은 라이브러리가 지원
-스프링프레임웍은 모든 플랫폼에서 사용이 가능한 프레임웍이다
-스프링은 웹분야 뿐만이 아니라 어플리케이션 모든 분야에 걸쳐 적용이 가능한 다양한 라이브러리를 가지고 있다.

 

2. Sping Cloud 적용한 마이크로 서비스 환경

 

: Spring Cloud는 분산 시스템에서 공통적인 패턴(구성 관리, 서비스 검색, 지능형 라우팅, 마이크로 프록시 등 )을 모아 신속하게 구축할 수 있는 도구를 스프링 라이브러리 형태로 제공한다.

따라서 개발자는 분산 시스템에서 필요한 부분들에 대한 부담을 덜고 충실하게 서비스의 기능을 구현하는 것에 충실할 수 있다. 또한 특정 벤더(AWS, Cloud Foundry 등)에 종속적이지 않기 때문에 다양한 분산 환경에서 잘 작동한다.

Spring Config : Spring Boot Application은 application.properties 혹은 application.yml 파일에 환경설정을 저장하고 이 파일의 정보를 읽어 빌드하는데, 이 파일들은 해당 프로젝트와 함께 저장된다. 
Spring Cloud Config 서버를 두어 사용하면 모든 Spring Boot Application의 환경설정 파일을 한 곳에 저장시킬 수 있고 해당 서버에 접근하여 환경설정 정보를 가져오도록 할 수 있다.
이렇게 적용하면 모든 Application의 환경설정 정보를 한곳에서 관리가 가능하고 환경설정이 바뀌어도 Application 전체를 다시 빌드하지 않아도 된다. 
하지만 우리 팀은 현재 Spring Config를 적용하지 않았다. 개발 초기에 적용했을 당시 개발 중에 환경설정이 바뀌면 바뀐 내용을 Spring Cloud Config 서버에 반영해야 해서 번거롭고 확인도 다시 해당 서버에서 해야하는 점이 불편하였다.

RabbitMQ : AMQP (Advanced Message Queueing Protocol) 로 만들어져 있으며 Message Queue를 제공한다. 
이상적인 마이크로서비스 환경은 마이크로서비스 사이의 통신이 비동기적으로 이루어지는 것인데, RabbitMQ를 사용하면 마이크로 서비스들이 외부의 Queue를 통해 메세지를 주고받도록 함으로써 쉽게 이 부분을 구성할 수 있다. 

Eureka : 마이크로서비스들의 정보를 레지스트리에 등록할 수 있도록 하고 마이크로서비스의 동적인 탐색과 로드밸런싱을 제공한다.

Zuul : 모든 마이크로서비스에 대한 요청을 먼저 받아들이고 라우팅하는 프록시 API Gateway 기능을 수행한다.

 

3. 애플리케이션 아키텍처

1. 계층형 아키텍처

  • 관심, 책임, 성격, 변하는 이유와 방식이 서로 다른 것들을 분리
  • 응집도가 높아지고 결합도가 낮아짐
  • 장점
    • 불필요한 부분까지 변경이 일어나고 이로 인해 작업이 더뎌지고 오류가 발생할 가능성이 적어짐
    • 어느 부분을 수정할지 파악하기 쉬워지고 변경이 필요한 부분만 각각 변경이 필요하고, 독립적인 발전이 가능
  • 이는 다음과 같이 나누어질 수 있다.
    • 데이터 엑세스 계층 : 데이터 엑세스 로직을 나누는 부분
    • 서비스 계층 : 비즈니스 로직을 담당하는 부분
    • 프레젠테이션 게층 : 웹을 처리하는 코드 또는 독자적인 성격의 코드
  • 위처럼 분리하면 독자적인 개발이 가능하며 테스트가 가능하고 개발과 변경 작업이 빨라진다. 구현 방법이나 세부 로직에 서로 영향을 주지 않고 변경할 수 있으므로 유연하다고 할 수 있다.
  • 프레젠테이션 계층의 오브젝트를 그대로 서비스 계층으로 전달하는 실수도 빈번하다고 함
    • HttpServletRequest , HttpSession 과 같은 타입을 서비스 파라미터로 전달하는 경우 → 서비스 계층에서 웹과 관련된 예외 발생 시 문제의 원인을 찾기 어려워짐

2. 오브젝트 중심 아키텍처

  • 도메인 모델을 반영하는 오브젝트 구조를 만들고 이를 각 계층 사이에서 정보를 전송하는데 사용
    • 객체지향 분석과 모델링 결과로 나오는 도메인 모델을 오브젝트 모델로 사용
    • 도메인 모델은 DB 엔티티 설계에도 반영 → 유사한 형태
  • DAO 는 자신이 DB 에서 가져와 도메인 모델 오브젝트에 담아주는 정보가 어떤 업무에 사용되는지 신경쓰지 않아도 됨
  • 오브젝트 중심 방식의 비즈니스 로직
public int calcTotalOfProductProce(Category category) {
	int sum = 0;
	for (Product product : category.getProducts()) {
		sum += product.getPrice();
	}
}

이와 같이 사용한다면 코드의 이해가 쉽고, 코드의 재사용성이 높아지는 구조로 만들 수 있음

  • 하지만 여기서 Category 오브젝트는 getter, setter 만 가지고 있는 빈약한 오브젝트라고 할 수 있음
    • 빈약한 오브젝트란 도메인 오브젝트에 정보만 담겨있고, 정보를 활용하는 아무 기능도 없는 오브젝트.
    • 이를 풍성한 오브젝트로 만들기 위해선 다음과 같이 변경할 수 있음
    public class Categoty {
    	...
    	List<Product> products;
    
    	public int calTotalOfProductsPrice() {
    		int sum = 0;
    		for (Product product : this.getProducts()) {
    			sum += product.getPrice();
    		}
    		return sum;
    	}
    }
    
    • 이와 같은 방식을 취하면 여러 서비스 오브젝트 계층에서 재사용할 수 있음
    • 따라서 도메인 스스로가 처리 가능한 기능과 도메인 비즈니스 로직을 갖도록 만드는 것이 바람직

 

4. DDD (Domain Driven Design) 란?

도메인(Domain)이란?

  • 어떤 웹 서비스를 만들 때 회원을 가입하고, 회원을 탈퇴하는 일련의 작업은 “회원” 과 관련된 일련의 작업들이며 여기서 “회원” 이라는 도메인이 있다고 볼 수 있습니다.

DDD

  • 도메인 주도 설계 (회원이 중심이 되어 개발하는 방식)
  • 도메인을 중심으로 하는 개발 방식 → 도메인에 관련된 문제를 해결하는 것
  • 복잡한 도메인을 해결하는 것을 높은 우선순위로 생각해 서비스를 만들어 나가는 방법
    • 도메인의 복잡성을 조금 더 쉽게 다룰 수 있게 해주는 도구

즉 , 각 도메인이 연결성이 적고 높은 정도로 연관되어 보다 가벼운 설계를 위해 탄생

DDD의 세가지 주요 원리

  1. 핵심 도메인과 그 기능에 집중하라.
  2. 도메인의 모델의 정교하게 구축하라.
  3. 어플리케이션 모델을 발전시키고 새롭게 생기는 도메인 관련 이슈를 해결하기 위해 도메인 전문가와 끊임없이 협력하라.

왜 등장하였는가

소프트웨어를 설계할 때 소프트웨어 설계는 처음에는 중요한 것들부터 작게 설계가 시작됩니다. 설계가 계속 진행되면서 팀원들은 본인이 담당하는 업무와 관련된 다양한 내용을 설계에 계속 추가하게 됩니다. 복잡한 도메인에 대한 이해와 탐구가 부족한 상태에서 각각의 담당 업무와 관련된 내용을 계속해서 식별하고 추가를 하게 됩니다. 이런 것들이 설계가 진행되는 내내 발생되고 반복되면서 비즈니스 상 중요한 것과 덜 중요한, 어쩌면 중요하지 않은 것들이 하나의 큰 덩어리로 얽히게 됩니다.

이렇게 만들어진 설계를 기반으로 구현된 코드는 가독성이 떨어지고, 또 많은 기능이 하나로 엮여 새로운 기능의 추가나 개선 등의 유지보수를 어려워지게 만드는 문제가 있습니다.

이런 문제를 방지하거나 최소화할 수 있는 설계 기법이 도메인 주도 설계입니다.

 

5. Entity, DTO, VO

Entity 란?

<aside> 💡 Entity Class는 실제 DataBase의 테이블과 1 : 1로 Mapping 되는 Class로, DB의 테이블내에 존재하는 컬럼만을 속성(필드)으로 가져야 한다. Entity Class는 상속을 받거나 구현체여서는 안되며, 테이블내에 존재하지 않는 컬럼을 가져서도 안된다.

</aside>

  • 최대한 외부에서 Entity Class의 Data Field에 함부로 접근하지 못하도록 제한
  • 해당 Class 안에서 접근을 허용할 데이터들을 제한하며 logic method을 구현
  • Domain Logic 만 가지며, Presentation Logic을 가지고 있어선 안됨
  • Spring 3 Tier인 Persistence, Buseniss, Presentation Tier 중 Persistence Tier에서 사용
  • 구현 method는 주로 Service Layer에서 사용,
    • Entity를 Persistence Tier에서 받아와 DTO로 변환하여Presentation Tier에 전달하는 것이 Business Tier, Service 단에서의 역할

DTO(Data Transfer Object) 란? 데이터 전달용

<aside> 💡 DTO(Data Transfer Object)는 데이터 전송(이동) 객체라는 의미를 가지고 있다. DTO는 주로 비동기 처리를 할 때 사용한다.

</aside>

  • DTO란 계층간 데이터 교환을 위한 객체
    • DB 의 데이터를 Service 나 Controller 등으로 보낼 때 사용하는 객체
    • DB의 데이터가 Presentation Logic Tier로 넘어올때는 DTO로 변환되어 오고감
    • 로직을 갖고 있지 않은 순수한 데이터 객체이며 getter / setter 만 갖는다. DB 에서 꺼낸 값은 변경할 필요가 없기에 setter 가 없음
  • Request와 Response용 DTO는 View를 위한 클래스
    • 자주 변경이 필요한 클래스
    • Presentation Model
    • toEntity() 와 같은 메서드를 통해서 DTO에서 필요한 부분을 이용하여 Entity로 변경
    • 또한 Controller Layer에서 Response DTO 형태로 Client에 전달

<aside> 💡 참고 entity 클래스와 DTO 클래스를 분리하는 이유

  • View Layer와 DB Layer의 역할을 철저하게 분리하기 위해
  • 테이블과 매핑되는 Entity 클래스가 변경되면 여러 클래스에 영향을 끼치게 됨
  • 반면 View와 통신하는 DTO 클래스(Request / Response 클래스)는 자주 변경되므로 분리해야 함
  • Domain Model을 아무리 잘 설계했다고 해도 각 View 내에서 Domain Model의 getter만을 이용해서 원하는 정보를 표시하기가 어려운 경우가 종종 있음.
  • 이런 경우 Domain Model 내에 Presentation을 위한 필드나 로직을 추가하게 되는데, 이러한 방식이 모델링의 순수성을 깨고 Domain Model 객체를 망가뜨리게 된다.
  • 또한 Domain Model을 복잡하게 조합한 형태의 Presentation 요구사항들이 있기 때문에 Domain Model을 직접 사용하는 것은 어렵다.
  • 즉 , DTO는 Domain Model을 복사한 형태로, 다양한 Presentation Logic을 추가한 정도로 사용하며 Domain Model 객체는 Persistent만을 위해서 사용한다.

</aside>

VO(Value Object) 란? 값 표현용

  • VO는 값 자체를 표현하는 객체
  • VO는 객체들의 주소가 달라도 값이 같으면 동일한 것으로 여김
    • 예를 들어, 고유번호가 서로 다른 만원 2장이 있다고 생각하자. 이 둘은 고유번호(주소)는 다르지만 10000원(값)은 동일하다. VO는 getter 메소드와 함께 비즈니스 로직도 포함할 수 있다. 단, setter 메소드는 가지지 않는다. 또, 값 비교를 위해 equals()와 hashCode() 메소드를 오버라이딩 해줘야 한다.
  • 아래 코드처럼 equals()와 hashCode() 메소드를 오버라이딩 하지 않으면 테스트가 실패한다.
// Money.java
public class Money {
    private final String currency;
    private final int value;

    public Money(String currency, int value) {
        this.currency = currency;
        this.value = value;
    }

    public String getCurrency() {
        return currency;
    }

    public int getValue() {
        return value;
    }
}

// MoneyTest.java
public class MoneyTest {
    @DisplayName("VO 동등비교를 한다.")
    @Test
    void isSameObjects() {
        Money money1 = new Money("원", 10000);
        Money money2 = new Money("원", 10000);

        assertThat(money1).isEqualTo(money2);
        assertThat(money1).hasSameHashCodeAs(money2);
    }
}
// Money.java
public class Money {
    private final String currency;
    private final int value;

    public Money(String currency, int value) {
        this.currency = currency;
        this.value = value;
    }

    public String getCurrency() {
        return currency;
    }

    public int getValue() {
        return value;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Money money = (Money) o;
        return value == money.value && Objects.equals(currency, money.currency);
    }

    @Override
    public int hashCode() {
        return Objects.hash(currency, value);
    }
}

// MoneyTest.java
public class MoneyTest {
    @DisplayName("VO 동등비교를 한다.")
    @Test
    void isSameObjects() {
        Money money1 = new Money("원", 10000);
        Money money2 = new Money("원", 10000);

        assertThat(money1).isEqualTo(money2);
        assertThat(money1).hasSameHashCodeAs(money2);
    }
}

💡 VO(Value Object) vs DTO VO는 DTO와 동일한 개념이지만 read only 속성을 가짐, VO는 특정한 비즈니스 값을 담는 객체이고, DTO는 Layer간의 통신 용도로 오고가는 객체를 말함

 

6. 데이터 중심 아키텍처의 문제점

 

일반적으로 비즈니스 로직은 서비스 계층에 존재해야 하지만 이런 구조에서 대부분의 비즈니스 로직들은 SQL과 프로시저로 만들어진다. 그래서 서비스 계층에 존재하게 될 로직은 흐름 제어 로직 밖에 없게 된다. 이런 구조는 간단한 처리 로직의 경우는 편하지만 업무가 복잡 해질수록 점점 그 복잡성을 제어할 수 없게 된다. 예를 들어 저장소를 교체한다고 했을 때, 기술과 비즈니스가 강하게 결합되어 있어 저장소를 변경하는 것도 쉽지 않게 된다. 

또 이런 구조에서는 성능 측면에서 대부분의 성능을 데이터베이스에 의존한다. 비즈니스 개념이 대부분 DB에 표현되기 때문이다. 따라서 데이터가 쌓여 감에 따라 DB의 성능은 지속적으로 감소할 수밖에 없다. 이를 최적화하는 방법으로 DB 서버의 사양 및 용량의 확장과 SQL 튜닝에 몰두할 수밖에 없게 된다. 그래서 클라우드 인프라를 사용 시에 큰 장점인 사용량에 대해 탄력적으로 대응하는 자동 스케일 아웃이 의미가 없어진다. 정작 바쁜 것은 DB이기 때문에 애플리케이션을 아무리 스케일 아웃해봐야 효과가 미미하다. 

요즘은 클라우드 자원환경에서 애플리케이션 자체의 성능 보다는 애플리케이션의 유연함이 좀 더 요구되는 시대이기 때문에 관심사의 분리 원칙에 따라 비즈니스 로직과 데이터 처리를 철저히 분리하는 것이 반드시 요구된다. 

 

7. 레이어드 아키텍처의 한계

일반적으로 프레젠테이션, 비즈니스, 데이터 액세스의 3계층으로 구분한다. 

레이어간 응집성을 높이고 의존도를 낮추기 위해 몇 가지 규칙들을 가지고 있다. 

상위 계층이 하위 계층을 호출하는 단방향성을 유지한다. 

상위 계층은 하위의 여러 계층을 모두 알 필요 없이 바로 밑의 근접 계층만 활용한다. 

상위 계층이 하위 계층에 영향을 받지 않게 구성해야 한다. 

하위 계층은 자신을 사용하는 상위 계층을 알지 못하게 구성해야 한다. 

계층 간의 호출은 인터페이스를 통해 호출하는 것이 바람직하다. 

 

계층 방식은 인터페이스를 통해 의존성을 낮춘다 해도, 일반적으로 인터페이스가 각 계층의 상위에 위치하는 구조로 제어의 흐름이 상위에서 하위로 흐르게 되고, 이에 따른 소스코드의 의존성은 제어의 흐름을 따르게 된다. 따라서 하위 계층의 유형이 추가되고 확장될 때 닫혀 있어야할 상위 계층이 영향을 받을 수밖에 없다. 

문제는 데이터 액세스 인터페이스의 위치인데, 데이터 액세스 인터페이스는 데이터 액세스 계층에 존재하는데 이런 방식은 항상 하위 계층에 의존하게 된다. 

비즈니스 로직을 보통 고수준 영역이라고 하고, 프레젠테이션, 데이터 액세스 계층을 저수준 영역이라고 한다. 고수준 영역은 핵심 영역이므로 보호를 받고, 저수준 영역의 변경, 확장에 영향을 받지 않아야 하는데, 일반적인 레이어드 아키텍처의 규칙만을 따르면 고수준 영역이 저수준 영역에 의존하게 되고 영향을 받게 된다. 

여기서 의존성 역전 원칙(DIP) 적용의 필요성이 생긴다. DIP는 데이터 액세스 계층이 구현해야 할 인터페이스를 고수준의 비즈니스 로직 계층에서 정의하게 함으로써 기존에 위에서 아래로 흘렀던 의존관계를 역전시키고 고수준이 저수준의 변경에 영향을 받지 않도록 해준다. 

하지만 레이어드 아키텍처에 DIP를 적용해도 한계가 존재한다. 프레젠테이션, 데이터 액세스 계층을 보통 저수준 계층으로 정의한다고 했는데 현대 애플리케이션은 이러한 2가지 계층 말고도 다양한 인터페이스를 필요로 한다. 애플리케이션을 호출하는 시스템의 유형과 애플리케이션과 상호작용하는 다양한 저장소가 존재하기 때문이다. 헥사고널 아키텍처는 이러한 문제점을 해결할 수 있다. 

 

DIP저수준 모듈이 고수준 모듈에 의존하게 되는 것 

 

8. 헥사고널 아키텍처

헥사고널 아키텍처는 엘리아스 쿡번이 제시한 아키텍처로 포트 엔 어댑터 아키텍처라고도 부른다. 

고수준의 비즈니스 로직을 표현하는 내부영역과 인터페이스를 처리를 담당하는 저수준의 외부 영역으로 나눈다. 

내부 영역은 순수한 비즈니스 로직을 표현하는 독립적인 영역이다. 그리고 외부영역과 연계되는 포트를 가지고 있다. 

외부 영역은 외부에서 들어오는 요청을 처리하는 인 바운드 어댑터와 비즈니스 로직에 의해 호출되어 외부와 연계되는 아웃 바운드 어댑터로 구성된다. 

 

 

가장 큰 특징은 고수준의 내부 영역이 어댑터에 전혀 의존하지 않게 한다는 것이다. 그것을 가능하게 하는 것이 내부 영역에 구성되는 포트이다. 

포트는 인 바운드 / 아웃 바운드 포트로 구분되는데, 인 바운드 포트는 내부 영역 사용을 위해 표출된 API이며, 외부 영역의 인 바운드 어댑터가 호출한다. 아웃 바운드 포트는 내부 영역이 외부를 호출하는 방법을 정의한다. 여기서 DIP 원칙과 같이 아웃 바운드 포트가 외부의 아웃 바운드 어댑터를 호출하여 외부 시스템과 연계하는 것이 아니라 아웃바운드 어댑터가 아웃 바운드 포트에 의존하여 구현된다. 

 

9. 클린 아키텍처 

클린 아키텍처는 로버트 세실 마틴이 제안한 아키텍처이다. 

클린 아키텍처는 여러 겹의 둘러싸인 영역으로 표현하며 엔티티, 유스케이스, 그 외 세부사항으로 구분한다. 

제일 중앙에는 엔티티가 있다. 엔티티는 업무 규칙을 캡슐화 한다. 모든 시스템에는 해당 도메인의 업무를 규정하는 핵심 업무 규칙들이 존재하는데, 보통 데이터를 요구한다. 따라서 핵심 업무 규칙과 데이터는 본질적으로 결합되어 있기 때문에 객체로 쉽게 만들 수 있다. 이런 유형을 엔티티 객체라고 한다. 

다음으로 엔티티를 감싸는 객체는 유스케이스이다. 유스케이스는 시스템의 동작을 사용자의 입장에서 표현한 시나리오이다. 해당 레이어의 소프트웨어는 시스템의 모든 유스케이스를 캡슐화하고 구현한다. 유스케이스는 엔티티와의 데이터 흐름을 조정하고, 엔티티가 유스케이스의 목표를 달성하도록 지시한다. 이 때 엔티티 같은 고수준은 저수준의 유스케이스를 알게 하면 안 된다. 

엔티티는 간단한 객체여야 하며 프레임워크, 데이터베이스 또는 여타 복잡한 것에 의존되어서는 안 되고 유스케이스 객체를 통해서만 엔티티를 조작해야 한다. 

다음으로 유스케이스를 감싸고 있는 모든 영역들은 세부사항이다. 세부사항은 인터페이스 어댑터와 프레임워크&디바이스 레이어가 있으며 인터페이스 어댑터는 유스케이스와 엔티티로부터, 데이터베이스나 웹 등 외부 기능에 용이한 형식으로 데이터를 변환해준다. 바깥 또는 안쪽으로 전달되는 데이터들을 전달받는 레이어에 맞게 변환시켜주는 역할을 한다. 

가장 바깥 쪽의 레이어는 일반적으로 프레임워크나 도구로 구성된다. 이 레이어에 있는 것들은 매우 빈번하게 변경되는 것이므로 추상화와 제어의 역전을  통해 변경으로부터 안전하게 만들어야 한다. 

 

10. 즉시로딩과 지연로딩

지연 로딩(LAZY)

  • 내부 매커니즘은 위의 그림과 같다.
  • 로딩되는 시점에 Lazy 로딩 설정이 되어있는 Team 엔티티는 프록시 객체로 가져온다.
  • 후에 실제 객체를 사용하는 시점에(Team을 사용하는 시점에) 초기화가 된다. DB에 쿼리가 나간다.
    • getTeam()으로 Team을 조회하면 프록시 객체가 조회가 된다.
    • getTeam().getXXX()으로 팀의 필드에 접근 할 때, 쿼리가 나간다.

대부분 비즈니스 로직에서 Member와 Team을 같이 사용한다면?

  • 이런 경우 LAZY 로딩을 사용한다면, SELECT 쿼리가 따로따로 2번 나간다.
  • 네트워크를 2번 타서 조회가 이루어 진다는 이야기이다. 손해다.
  • 이때는 즉시 로딩(EAGER) 전략을 사용해서 함께 조회하면 된다.
즉시 로딩(EAGER)
  • fetch 타입을 EAGER로 설정하면 된다.
  • 대부분의 JPA 구현체는 가능하면 조인을 사용해서 SQL 한번에 함께 조회하려고 한다.
  • 이렇게 하면, 실제 조회할 때 한방 쿼리로 다 조회해온다.(실제 Team을 사용할 때 쿼리 안나가도 된다.)
  • 실행 결과를 보면 Team 객체도 프록시 객체가 아니라 실제 객체이다.

지연 로딩 활용

  • Member와 Team을 자주 함께 사용한다 -> 즉시 로딩
  • Member와 Order는 가끔 사용한다 -> 지연 로딩
  • Order와 Product는 자주 함꼐 사용한다 -> 즉시 로딩
  • 위와 같이 설정해 놓고 쓸 수 있지만, 굉장히 이론적인 개념이고
  • 실무에서는 다 LAZY로 쓰자. 즉시 로딩 사용하지 말자.
  • JPQL fetch join이나, 엔티티 그래프 기능으로 해결하자.
  • 즉시 로딩은 상상하지 못한 쿼리가 나간다.

11. JPAL 페치 조인

 

이 구조에서 일반적인 조인을 사용하였을 때

실제 JPA에서 생성하는 쿼리문을 보면 Member를 조회하는 쿼리 1개를 날렸을 뿐인데, Team1과 Team2를 조회하는 쿼리 2개가 추가로 나가게 되는 1+N 문제가 발생하게 된다. 

이때, 페치 조인을 사용한다면 1+N 문제를 해결할 수 있다.

List<Member> resultList = em.createQuery("select m from Member m join fetch m.team", Member.class).getResultList();

페치 조인을 사용하여 실행한다면 결과 쿼리 1개로 한번에 조회가 된다.

 

 

References

WAS
Bean의 생명주기와 Bean Scope
SpringCloud
API Gateway
Spring Cloud Netflix with Docker

https://velog.io/@gillog/Entity-DTO-VO-바로-알기

마이크로서비스 내부아키텍처 - 2회 : 클린 아키텍처와 헥사고널 아키텍처 | SK(주) C&C’s TECH BLOG (engineering-skcc.github.io) 

즉시로딩과 지연로딩

페치 조인

댓글