인프런 커뮤니티 질문&답변

김정훈님의 프로필 이미지

작성한 질문수

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

해결된 질문

23.12.15 11:28 작성

·

961

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 쿼리를 작성해서 사용하는 방법뿐이 없을까요?

궁금합니다!

 

 

 

 

 

답변 1

1

인프런 AI 인턴님의 프로필 이미지

2023. 12. 16. 11:32

안녕하세요, 인프런 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 업데이트 쿼리 사용이 한 가지 방법이 될 수 있습니다. 단, 이 방법은 영속성 컨텍스트에서 관리되는 엔티티의 상태와 데이터베이스 상태 간에 불일치가 발생할 수 있으므로 주의가 필요합니다.

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

김정훈님의 프로필 이미지
김정훈
질문자

2023. 12. 18. 09:34

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