inflearn logo
강의

강의

N
챌린지

챌린지

멘토링

멘토링

N
클립

클립

로드맵

로드맵

지식공유

[Spring JPA] .save() 대해 문의 드립니다.

해결된 질문

1304

김정훈

작성한 질문수 4

0

4개의 테이블 (a, b, c, d)

각각 1:N 관계 입니다. a-b 1:N, b-c 1:N , c-d 1:N (fetchType = LAZY)

네개의 테이블에 대한 정보를 fetchjoin을 통해서

List<a> 객체로 리턴 받았습니다.

 

List<a> 객체를 루프를 돌면서 a 객체 값에 특정 필드를 변경하고 .save()를 호출 했더니

update 쿼리만 나가는게 아니고

1) a 테이블의 id(pk)값의 조건 select 쿼리 1회

2) b 테이블 조건절에는 id(FK) select 쿼리 1회

3) 위에서 값이 조회될경우 c테이블에 b테이블 결과 id(PK) 값들로 IN 쿼리 1회

4) d 테이블 3)과 동일한 구조로 IN쿼리 1회

5) 최종 udpate 쿼리 호출

이런식의

마치 해당 a 객체 전체 데이터(하위 포함)를 조회 했을떄 날라가는 select쿼리가 모두 호출 되었습니다.

 

예)

List<a> result = aRepository.getFetchJoinQuery();

result.stream().forEach(a -> {

a.setName("HOON");

aRepository.save(a); -> 해당 시점 위 쿼리 호출됨

logger.info("xxxxxx");

});

 

디버깅으로 확인한 내용이구요,

혹시나 디버깅 모드에서 데이터 확인중에 날아간 쿼리인가 해서 디버깅없이 RUN으로

실행했을때도 동일하게 쿼리가 발생하는것이 확인 되었습니다..

 

save() 사용시에 select 쿼리 발생은 어쩔수 없는걸까요?

어쩔수 없다면 save() 메서드 대신 그냥 JPQL로 update 쿼리를 작성해서 사용하는 방법뿐이 없을까요?

궁금합니다!

 

 

 

 

 

김영한 jpa springjpa

답변 1

1

인프런 AI 인턴

안녕하세요, 인프런 AI 인턴입니다.

김정훈님, Spring Data JPA에 있는 .save() 메서드의 작동 방식에 대해 질문해주셨군요. 해당 메서드는 기본적으로 Spring Data JPA의 CrudRepository.save(…)를 사용하여 엔티티를 저장합니다. 만약 엔티티가 새로운 것이 아니라면, 즉 이미 데이터베이스에 존재하는 엔티티라면, Spring Data JPA는 entityManager.merge(…) 메서드를 호출해서 엔티티를 업데이트하게 됩니다. 이 과정에서 엔티티의 현재 상태를 데이터베이스에 있는 상태와 비교하기 위해 추가적인 SELECT 쿼리가 발생할 수 있습니다.

JPA는 엔티티의 상태를 추적하고, 엔티티가 관리 상태가 되면 변경 감지(dirty tracking)을 통해 엔티티의 변경된 부분만 데이터베이스에 반영합니다. 하지만, save()를 호출할 때 JPA가 엔티티의 이전 상태를 알아내기 위해 먼저 조회를 하게 되는 경우도 생길 수 있고, 이는 추가적인 쿼리가 발생하는 원인이 될 수 있습니다.

만약 save() 사용 시 발생하는 SELECT 쿼리가 성능에 문제를 일으키거나 원치 않는 상황이라면, JPQL 또는 @Query 어노테이션을 사용한 업데이트 쿼리를 직접 작성해서 사용하는 방법을 고려하실 수 있습니다. 이 방식을 사용하면 엔티티의 모든 레코드를 조회하지 않고, 필요한 필드만을 대상으로 업데이트 하는 쿼리를 직접 실행시킬 수 있습니다.

자세한 정보는 공식 문서에서 확인하실 수 있습니다.

이와는 다르게 스프링 데이터 JDBC를 사용할 경우, .save() 메서드 작동 방식이 좀 더 단순합니다. 스프링 데이터 JDBC는 엔티티의 이전 상태를 모르고 변경 감지를 하지 않기 때문에 매번 전체 엔티티를 저장할 때 DELETE와 INSERT 쿼리가 발생합니다. 이는 다른 제한 사항을 고려할 때 낭비적일 수 있지만, 스프링 데이터 JDBC의 현재 설계상의 한계입니다.

굳이 모든 데이터를 조회하지 않으려면, 수정이 필요한 필드만을 명시하는 JPQL 업데이트 쿼리 사용이 한 가지 방법이 될 수 있습니다. 단, 이 방법은 영속성 컨텍스트에서 관리되는 엔티티의 상태와 데이터베이스 상태 간에 불일치가 발생할 수 있으므로 주의가 필요합니다.

추가적으로 필요한 내용이나 더 궁금한 점이 있으면 문의해주시기 바랍니다.

0

김정훈

그런 이유에서 였군요.. 매번 자세한 답변 감사드립니다.

RepositoryTest의 패키지 위치가 domain인 이유

0

16

1

도메인 모델에서 관계와 규칙을 구분하는 방법

0

31

2

16 강의 메세지 retryCount의 의도

0

16

2

JPA Repository 질문이 있습니다!

1

29

2

페이지네이션 처리를 쿼리에서 하는 방식 질문

1

31

1

UserService, CertificationService 책임 분리 기준 질문

0

22

1

실무 조언 관련 질문입니다.

0

38

1

sdk 설정 오류

0

43

2

H2데이터베이스 파일 생성

0

46

2

SpringBoot 4.X에서의 Querydsl 설정

0

67

2

REQUIRES_NEW 해결 방법에 대해서 질문있습니다!!

0

25

1

오탈자 - @Transactional

0

52

1

Dto와 Entity 사용 관련 질문

0

29

2

서브쿼리 강의에서 ALL 예시 관련 질문드립니다.

0

48

2

EC2 실습 중 docker-compose / docker ps 실행 시 권한 오류 문의

2

67

1

application.properties 작성 관련 질문

0

43

2

색깔구분

0

38

2

gradlew, java -jar 로 애플리케이션 실행시키기에서

1

44

1

리액트 관련 질문이 있습니다.

0

59

2

강의 관련 외 질문입니다.

0

62

2

update()에 사용하는 setter 질문드립니다.

0

43

1

스프링부트 버전

0

64

2

querydsl 오픈소스에 대한 질문

0

66

1

"스프링 부트와 리액트로 구현하는 소셜 로그인" 강의와 차이점이 궁금합니다.

0

48

1