내일배움캠프 55일차 TIL _ 12주 2일차
2024. 7. 2. 22:56ㆍTIL Java
- 오늘 있었던 일
- 스프링 복습및 모의 면접 준비
모의 면접 준비
● 예상 문제 1
더보기
Lazy Loading, Eager Loading 차이점과 장단점
로딩의 설명
Lazy Loading (지연 로딩)
지연 로딩은 데이터를 필요할때까지 전송 하지 않는 방법
LAZY는 부모 Entity가 호출되면 부모 혼자 로딩된 상태이고 연관관계가 설정된 Entity가 필요한 경우에 해당 객체를 로드하는 사용할 수 있다.
- 특징
- 데이터를 처음부터 로드하지 않고, 해당 데이터가 실제로 요청될 때 로드합니다.
- 객체의 초기화가 지연되어, 데이터베이스 쿼리도 지연됩니다.
- 장점
- 메모리 절약: 필요하지 않은 데이터는 로드되지 않기 때문에 메모리 사용량이 줄어듭니다.
- 성능 최적화: 초기 로딩 시간이 줄어들어 애플리케이션의 초기 응답 속도가 빨라집니다.
- 리소스 절약: 데이터베이스 접근을 최소화하여 리소스 사용을 절약합니다.
- 순환 참조 방지: 객체 간의 연관관계에서 순환 참조가 발생할 확률이 줄어듭니다. 객체를 조회할 때 실제로 필요한 데이터만 로딩되므로 무한한 순환 참조를 방지할 수 있습니다.
- 단점
- 지연 시간: 데이터가 필요한 순간에 로드되므로, 그 시점에 지연이 발생할 수 있습니다.
- 복잡성 증가: 코드를 이해하고 유지보수하는 데 더 많은 복잡성이 추가됩니다.
- N+1 문제: 잘못된 사용으로 인해 반복적인 데이터베이스 쿼리가 발생할 수 있습니다.
Eager Loading (즉시 로딩)
즉시 로딩은 데이터 전부를 즉시 전송 하는 방법
EAGER는 부모 Entity가 호출되면 즉시 로딩되어 메모리에 존재하여 언제든 사용할 수 있는 상태
- 특징
- 객체를 처음 로드할 때 관련된 모든 데이터를 한꺼번에 로드합니다.
- 여러 테이블을 조인(join)하여 한번에 데이터를 가져오는 방식으로 구현됩니다.
- 장점
- 즉시 사용 가능: 필요한 데이터가 미리 로드되어 있기 때문에 접근 시 지연이 없습니다.
- 쿼리 수 감소: 한 번의 데이터베이스 쿼리로 필요한 모든 데이터를 가져오므로 쿼리 수가 줄어듭니다.
- 간결성: 코드가 더 단순해지고 예측 가능성이 높아집니다.
- 메모리 사용 증가: 불필요한 데이터를 로드하여 메모리 사용량이 증가할 수 있습니다.
- 초기 로딩 시간 증가: 모든 데이터를 한 번에 로드하기 때문에 초기 로딩 시간이 길어질 수 있습니다.
- 리소스 낭비: 필요한 데이터보다 더 많은 데이터를 로드하여 리소스를 낭비할 가능성이 있습니다.
● 예상 문제 2
더보기
N +1 문제
연관 관계에서 발생하는 이슈로 연간관계가 설정된 엔티티를 조회할 경우 조회된 데이터 갯수(n)만큼 연관관계의 조회 쿼리가 추가로 발생하여 데이터를 읽어오는 현상
원인
- 지연 로딩(Lazy Loading) 설정이 부족한 경우: 기본적으로 JPA는 연관 관계를 지연 로딩으로 설정하여, 엔티티를 가져올 때 연관된 엔티티들을 로딩하지 않습니다. 하지만 연관 엔티티들을 사용할 때마다 데이터베이스 쿼리를 실행하여 데이터를 가져오게 되면, 매번 연관 엔티티를 가져오기 위한 추가 쿼리가 실행될 수 있습니다.
- 연관 엔티티의 수가 많을 때: 예를 들어, 한 개의 부모 엔티티와 여러 개의 자식 엔티티가 있을 때, 부모 엔티티를 가져올 때 연관된 모든 자식 엔티티들을 가져와야 하는 상황이 발생할 수 있습니다. 이 경우 부모 엔티티를 가져올 때마다 N개의 추가 쿼리가 실행될 수 있습니다(N+1).
- JPQL을 통해 대상이 되는 객체 정보가 담긴 Row를 조회 연관관계를 무시한 상태로 다른 엔티티의 데이터가 필요한 Row조회
해결방법
- 페치 조인(Fetch Join) 사용: JPA의 페치 조인을 사용하여 연관 엔티티들을 한 번에 함께 조회할 수 있습니다. 이를 통해 추가적인 쿼리 실행 없이 필요한 데이터를 모두 가져올 수 있습니다.
- SQL를 이용하는 것과 유사하며 inner join형태로 데이터베이스에 전송됩니다.
- JpaRepository를 구현하는 별도의 메서드에 밑의 에너테이션을 사용해 설정합니다.
-
@Query(SELECT p FROM ParentEntity p JOIN FETCH p.children)
- 다만 이를 사용하면 FetchType은 사용할 수 없고 페이징 쿼리 또한 사용할 수 없습니다.
- 일대다 관계에서의 배치 크기( @BatchSize(size = 10) ) 설정:이를 이용해 한번에 가져오는 쿼리의 양을 최적화 하는방법입니다. N +1 문제가 수천번이 발생한다고 할떄 특정 회수만 반복하는 방식입니다.
- 애플리케이션 전체에 적용할때는 .yml 또는 application.properties 에서 IN절에 올 수 있는 최대 횟수를 뜻하는 size를 조절하면 됩니다.
- @BatchSize 애너테이션을 N+1 문제의 원인이 되는 Entity의 필드에 설정하는 방법도 있습니다.
-
@OneToMany(mappedBy = "parent") @BatchSize(size = 10) private List<ChildEntity> children;
- 연관 관계의 FetchType 설정: 기본적으로 JPA는 일대다 관계에서는 연관 엔티티를 지연 로딩으로 설정합니다. 따라서 필요에 따라 명시적으로 FetchType을 설정하여 지연 로딩을 강제할 수 있습니다.
- FetchMode.SUBSELECT : Hibernate에서 제공하는 특정한 fetch 모드로 Hibernate는 연관된 엔티티들을 일반적으로 쿼리를 통해 가져오지만, FetchMode.SUBSELECT를 사용하면 추가적인 쿼리를 하나의 서브쿼리로 모아서 처리합니다.
- 단일 쿼리 실행: 기본 쿼리와 서브쿼리를 통해 모든 연관 엔티티들을 한 번에 가져오기 때문에 N+1 문제를 방지할 수 있습니다.
- 성능 향상: 서브쿼리를 사용하여 데이터베이스의 부하를 줄일 수 있습니다.
-
@Entity public class ParentEntity { @OneToMany(mappedBy = "parent", fetch = FetchType.LAZY) @Fetch(FetchMode.SUBSELECT) private List<ChildEntity> children; }
- QueryDSL은 JPA를 편리하게 사용할 수 있도록 도와주는 라이브러리로, 동적 쿼리를 작성하고 실행하는 데 유용합니다. N+1 문제를 해결하기 위해 QueryDSL을 사용할 때는 fetch join을 활용하여 연관 엔티티를 한 번에 가져오는 방식으로 문제를 해결할 수 있습니다.
- 이런 방식으로 SQL문과 유사하게 사용 할 수 있습니다.
-
.QParentEntity parentEntity = QParentEntity.parentEntity; List<ParentEntity> parents = new JPAQuery<>(entityManager) .select(parentEntity) .from(parentEntity) .leftJoin(parentEntity.children, QChildEntity.childEntity).fetchJoin() .fetch();
- @EntityGraph는 JPA에서 성능 최적화를 위해 사용되는 기능 중 하나로, 엔티티 그래프(Entity Graph)를 정의하여 연관된 엔티티들을 한 번에 조회하는 방법을 제공합니다. 이를 통해 N+1 문제를 해결하고 성능을 향상시킬 수 있습니다.
- @EntityGraph를 사용하여 특정 엔티티와 그 엔티티의 연관 엔티티들을 한 번에 로딩할 수 있습니다. 이를 통해 필요한 데이터를 최소한의 데이터베이스 쿼리로 가져올 수 있습니다.
- 지연 로딩(Lazy Loading)을 강제적으로 즉시 로딩(Eager Loading)으로 설정할 수도 있습니다. 이는 @NamedEntityGraph를 사용하여 정의할 수 있습니다.
-
@Entity public class ParentEntity { @OneToMany(mappedBy = "parent", fetch = FetchType.LAZY) @EntityGraph(attributePaths = "children") private List<ChildEntity> children; }
추천 해결 방법
페치 조인(Fetch Join) 사용:
- 페치 조인을 사용하여 연관된 엔티티들을 한 번에 로딩할 수 있습니다.
- 이 방법은 가장 직관적이고 효과적이며, 기존의 쿼리를 조금 수정하는 것만으로 N+1 문제를 해결할 수 있습니다.
@EntityGraph 사용:
- @EntityGraph를 사용하여 엔티티 그래프를 정의하고, 필요한 연관 엔티티를 한 번에 로딩할 수 있습니다.
- 이 방법은 특히 복잡한 연관 관계에서 유용하며, 코드의 가독성을 높이고 유지보수성을 높일 수 있습니다.
QueryDSL을 사용한 fetch join:
- QueryDSL을 활용하여 동적 쿼리를 작성하고, fetch join을 사용하여 필요한 연관 엔티티를 한 번에 로딩할 수 있습니다.
- 이 방법은 복잡한 쿼리를 작성해야 할 때 유용하며, 쿼리의 성능을 향상시키는 데 도움을 줍니다.
● 예상 문제 3
더보기
트렌지션( Transaction )
트랜잭션(Transaction)은 데이터베이스 관리 시스템(DBMS)에서 여러 개의 작업을 하나의 논리적 단위로 묶어서 처리하는 방법입니다. 트랜잭션은 ACID라는 속성을 준수하여 데이터의 일관성, 정확성, 독립성을 보장합니다.
ACID 속성
- 원자성(Atomicity):
- 트랜잭션의 모든 작업이 완전히 수행되거나 전혀 수행되지 않아야 합니다.
- 즉, 트랜잭션 내의 작업 중 하나라도 실패할 경우 다른 모든 작업도 롤백되어야 합니다.
- 일관성(Consistency):
- 트랜잭션이 수행되기 전과 후에 데이터베이스는 일관된 상태를 유지해야 합니다.
- 즉, 모든 제약 조건(Constraints)이 만족되어야 합니다.
- 고립성(Isolation):
- 동시에 실행되는 여러 트랜잭션이 서로 영향을 미치지 않고 독립적으로 수행되어야 합니다.
- 하나의 트랜잭션이 다른 트랜잭션의 연산을 볼 수 없으며, 다른 트랜잭션이 완료되기 전까지는 그 결과를 참조할 수 없어야 합니다.
- 지속성(Durability):
- 트랜잭션이 성공적으로 완료되면 그 결과는 영구적으로 반영되어야 합니다.
- 시스템 장애나 기타 문제가 발생해도 데이터베이스의 상태는 유지되어야 합니다.
트랜잭션의 특징
- 시작(Start): 트랜잭션이 시작됩니다.
- 커밋(Commit): 모든 작업이 성공적으로 완료되었고, 데이터베이스의 상태를 변경사항을 영구적으로 저장하기 위해 커밋됩니다.
- 롤백(Rollback): 트랜잭션 중에 문제가 발생하여 트랜잭션을 취소하고 이전 상태로 되돌립니다.
트랜잭션의 사용 예
일반적으로 다음과 같은 상황에서 트랜잭션이 사용됩니다:
- 은행 업무: 계좌 이체와 같은 금융 거래는 원자성을 보장해야 합니다. 송금과 수신이 동시에 일어나거나 일부만 성공하는 상황을 방지하기 위해 트랜잭션이 사용됩니다.
- 예약 시스템: 좌석 예약과 같은 다중 사용자 간의 동시 업무에서 일관성과 고립성이 중요합니다. 한 좌석이 동시에 여러 명에게 예약되지 않도록 트랜잭션을 사용하여 관리합니다.
- 인터넷 쇼핑몰 주문 처리: 장바구니에서 주문으로의 상태 전환 과정에서 일관성과 지속성이 보장되어야 합니다.
당일 회고
- 모의 면접... 긴장된다.
'TIL Java' 카테고리의 다른 글
내일배움캠프 57일차 TIL _ 12주 4일차 (0) | 2024.07.08 |
---|---|
내일배움캠프 56일차 TIL _ 12주 3일차 (0) | 2024.07.08 |
내일배움캠프 54일차 TIL _ 12주 1일차 (0) | 2024.07.01 |
내일배움캠프 53일차 TIL _ 11주 5일차 (0) | 2024.06.28 |
내일배움캠프 52일차 TIL _ 11주 4일차 (0) | 2024.06.27 |