JPA Troubleshooting

이종찬·2023년 3월 6일
0

📖 JPA Troubleshooting?

개체와 데이터베이스간의 테이블 매핑이 올바르게 설정하지 않은 경우, 엔티티 어노테이션이 적합하지 않은 경우 등에 문제로 JPA Entity 문제가 발생할 수 있습니다. 또한 엔티티의 수명 주기, 영속성 컨텍스트, 스키마 등의 문제가 있는 경우 데이터베이스에 문제가 발생할 수 있습니다.

위와 같이 JPA를 사용할 때 발생하는 문제를 식별하고 해결하는 프로세스를 JPA Troubleshooting이라고 합니다. 주로 JPA Entity, 영속성 문제 식별, 컨텍스트 혹은 기본 데이터베이스의 문제 식별이 포함됩니다.

JPA Troubleshooting의 방법은 다음과 같습니다.

1. 문제식별

오류 메시지 검사, 로그 확인, 문제 재현을 위한 테스트 실행을 하여 어떤 문제가 발생했는지 정확하게 인지하여야 합니다.

2. 코드 검토

식별한 문제를 토대로 코드를 검토하여 문제를 일으킬 수 있는 것들을 확인합니다. 주로 JPA Entity, 영속성 컨텍스트, JPA 관련 코드에서 문제를 찾습니다.

3. database 검토

JPA를 사용하여 데이터를 유지, 검색하는 것에 문제가 발생한 경우 데이터베이스에 문제가 있을 수 있습니다. 데이터베이스가 실행중인지, 필요한 데이터 및 데이터 무결성 문제를 점검해야 합니다.

4. 디버깅 도구 활용

위와 같은 단계를 거침에도 불구하고, 문제가 해결되지 않은 경우 디버깅 도구를 활용하는 것이 좋습니다. Java IDE에 코드를 단계 별로 실행하여 문제를 식별하는 것에 도움을 줍니다.

5. 문서 참조

JPA에 대한 문서를 참조하는 방법입니다. 비슷한 문제를 직면하고 해결한 개발자들의 리소스를 참조하거나 이해가 되지 않는 동작은 공식 문서를 참조하는 것이 좋습니다.

🤔 사용해야 하는 이유는?

JPA는 디버그가 어려울 수 있는 작업입니다. 즉, 문제 해결을 하기 위한 효율적인 작업이 필요합니다. JPA 문제 해결에 구조화된 접근 방식으로 빠르고 효율적으로 문제를 식별하고 해결할 수 있습니다. 또한 안정성을 보장하는데 도움이 될 수 있습니다. 프로세스 초기에 문제를 식별하여 잠재적인 문제를 미리 해결할 수 있습니다.

😮 사용되는 사례

  1. JPA를 사용할 때 예기치 않은 동작 발생
  2. 버전에 대한 호환성 문제가 생긴 경우
  3. 비효율성을 식별하여 성능을 최적화 하는 경우

전반적으로 더 나은 품질의 JPA 기반 애플리케이션을 만들기 위해 사용됩니다. 구조화된 접근 방식과 적절한 도구 및 리소스를 활용하여 효율적으로 문제식별 및 해결하는 것에 초점을 맞춥니다.

✅ JPA를 사용하면서 해결해야 할 문제들

1. N-1 이슈

JPA가 과도한 데이터베이스 쿼리를 수행할 때 발생되는 문제입니다. 다른 엔티티와 일대다 관계를 가지며 지연 로딩을 사용하는 경우 관련 데이터를 검색하기 위한 추가 쿼리를 수행합니다. 이때 N+1문제(일괄적으로 처리 가능한 것들을 한개씩 N번 처리하는 현상)가 발생 하게 됩니다.

해결 방안

1. fetch join

부모 객체와 함께 연관 관계 또는 value collection을 초기화 하는데 사용됩니다. JPQL를 사용하여 단일 select를 통해 이루어집니다. 이는 특히 collection의 경우 유용하며 매핑 파일의 외부 조인 및 지연 선언을 실질적으로 무시합니다.

@Query("select r from Review r join fetch r.comments")
List<Review> findAllByFetchJoin();

해당 메서드를 실행하게 되면 select 쿼리에 조인 패치가 적용되어 한번의 쿼리로 데이터를 가져오게 됩니다.

2. @EntityGraph

쿼리와 독립적으로 이루어지며 데이터베이스에서 가져올 속성을 정의합니다. fetch 또는 load 그래프로 사용할 수 있습니다. 메소드 또는 쿼리에 적용할 수 있으며 attributePaths를 사용하여 엔티티 그래프를 적용할 필드를 지정할 수 있습니다.

@EntityGraph("attributePaths = "comments")
@Query("select r from Review r")
List<Review> findAllByEntityGraph();

OR

@EntityGraph("attributePaths = "comments")
List<Review> findAll();

해당 메서드를 실행하게 되면 조인 패치를 적용한 것과 동일하게 됩니다.

JPA에서 Entity와 관계를 맺을 때 여러 번의 쿼리가 발생하는 상황을 해결할 수 있습니다.

하지만, 데이터를 한번에 가져오는 처리가 무조건 좋은 것은 아닙니다.

연관된 엔티티의 수만큼 결과가 늘어나 페이징처리가 불가능합니다. 또한 연관된 엔티티들의 조합에 따라 결과가 증가하며 LAZY 패치로 지정한 속성들도 조회하여 중복된 데이터가 많이 생길 수 있습니다. 즉, 오히려 복잡한 쿼리를 생성할 수 있으며 필요하지 않은 데이터까지 가져올 수 있습니다.

상황에 따라 잘 사용하는 것이 좋습니다.

2. 영속성 컨텍스트로 인해 발생하는 이슈**

영속성 컨텍스트는 JPA에서 관리되는 엔티티 집합을 나타내는 개념입니다. 데이터베이스에서 데이터를 가져오거나 업데이트 등의 작업을 할 때 영속성 컨텍스트를 관리하여 변경 사항을 데이터베이스와 적절하게 동기화하도록 합니다. 이러한 과정에서 몇가지 문제가 발생할 수 있습니다.

1. Detached Entities issue

준영속 상태에서 작업을 수행하고 데이터베이스에 영속하는 경우 예기치 않은 동작이 발생할 수 있습니다. 데이터베이스의 데이터가 다른 프로세스나 사용자에 의해 수정된 경우 영속성 컨텍스트가 데이터의 현재 상태와 동기화 되지 않을 수 있습니다.

2. Lazy loading issue

JPA의 LAZY를 사용하여 데이터를 필요에 따라 로드할 수 있으므로 성능이 향상될 수 있지만 영속성 컨텍스트외부에서 느리게 로드된 데이터에 엑세스하려고 하면 오류가 발생할 수 있습니다.

해당 이슈들을 해결하려면 영속성컨텍스트를 적절하게 관리하고 준영속 상태의 엔티티, LAZY 처리된 부분을 어떻게 사용되는지 알아야 합니다. 또한 트랜잭션이 어떻게 사용되었는지 확인하여 제대로 동기화 되었는지 확인해야 합니다.

3. Dirty check

상태 변경 검사라고도 불리며 JPA에서 트랜잭션이 끝나는 시점에 변화가 있는 모든 엔티티 객체를 데이터베이스에 자동으로 반영해줍니다. 이 때 변화 유뮤의 기준을 최초로 조회한 상태를 기준으로 dirty checking을 하게 됩니다. 예를 들면 엔티티 객체를 변경하고 save를 호출하지 않아도 변화를 감지하고 반영하는 과정입니다.

장점
해당 기술의 장점은 엔티티 객체의 상태 변화를 자동으로 감지하기 때문에 udpate 쿼리 작성, save 호출할 필요가 없습니다. 최초상태와 비교를 하여 변화가 있는 경우만 쿼리를 실행하기 때문에 불필요한 쿼리 실행을 줄일 수 있습니다.

단점

엔티티 객체의 상태 변화를 감지하기 위해 메모리에 스냅샷을 저장하고 비교하는 과정이 많은 리소스와 시간을 소모할 수 있습니다. 또한 트랜잭션 커밋 시점에 자동으로 데이터베이스에 반영이 되므로 개발자가 의도하지 않은 데이터 변경이 일어날 수 있습니다.

✅ 요약

  • JPA를 사용함에 있어 문제 식별 및 해결하는 방법을 JPA TroubleShooting이라고 합니다.
  • JPA는 디버그가 어렵기 때문에 JPA 문제 해결을 효율적으로 하는 과정이 도움이 됩니다.
  • N - 1 이슈를 해결하려면 join fetch, @EntityGraph를 사용하는 방법이 있습니다.
  • 영속성 컨텍스트로 발생하는 이슈는 준영속 상태, 트랜잭션을 확인하여 예방할 수 있습니다.
  • Dirty check를 사용하여 수정,저장에 사용되는 쿼리를 줄일 수 있지만 의도하지 않은 데이터 변경이 일어날 수 있으며 리소스가 많이 들 수 있다.
profile
왜? 라는 질문이 사라질 때까지

0개의 댓글