11월 6일

Yullgiii·2023년 11월 6일
0
post-thumbnail

내일 배움 캠프

JPA의 영속성과 관련된 핵심 개념

엔터티 (Entity)

엔터티는 JPA에서 중요한 개념 중 하나로, 데이터베이스의 테이블과 1:1로 매핑되는 자바 객체를 의미한다. 이러한 엔터티를 사용함으로써 개발자는 데이터베이스의 테이블을 직접 조작하는 대신에 객체 지향적인 방식으로 데이터를 관리할 수 있게 되는것이다.

엔터티의 동등성

엔터티는 식별자 값 (@Id로 정의된 필드의 값)을 기반으로 동등성을 비교해야 한다.
즉, 엔터티 인스턴스의 주소값이 아닌 식별자 값을 기반으로 동등성을 판단하게 된다!!!!

엔터티는 JPA의 핵심 기능으로, 데이터베이스와의 작업을 객체 지향적으로 처리할 수 있도록 돕게 된다. 이를 통해 데이터베이스 테이블과의 직접적인 작업 없이도 데이터를 관리하고, 다른 객체들과의 관계도 설정할 수 있게 된다.

1. 영속성이란?(Persistence)

영속성은 데이터를 생성한 프로그램의 수명이 끝나도 사라지지 않는 데이터의 특성을 의미하는데 JPA(Java Persistence API)에서는 이를 위해 RDBMS와 같은 외부 저장소를 사용하여 객체 데이터를 영구적으로 저장한다!!!

2. 엔터티 매니저 (Entity Manager)

Entity Manager는 JPA의 핵심적인!!!! 부분으로, 엔터티의 생명 주기를 관리하고 데이터베이스와의 모든 상호작용을 처리합니다. 주요기능으로서는

  • 엔터티의 CRUD(Create, Read, Update, Delete) 연산 수행.
  • 쿼리를 통한 데이터베이스 검색.
  • 연관된 엔터티 관리.

3. 엔터티 매니저 팩토리 (Entity Manager Factory)

Entity Manager 인스턴스를 만드는 공장 역할을 한다. 애플리케이션의 시작 시점에 단 한 번만 생성되어야 하고, 이 팩토리를 통해 여러 Entity Manager 인스턴스들이 생성된다. 각각의 스레드나 요청은 자신만의 Entity Manager 인스턴스를 사용해야 하기 때문에, 스레드 간의 안전성을 보장받을 수 있다.

4. 엔터티의 생명주기

JPA 엔터티는 명확한 생명 주기를 가지며, 이는 다음과 같다:

  • 비영속 (New/Transient): 엔터티가 생성되었지만 아직 영속성 컨텍스트와 관계가 없는 상태.
  • 영속 (Managed): 엔터티가 영속성 컨텍스트에 저장되어 관리되는 상태.
  • 준영속 (Detached): 한 번 영속 상태였던 엔터티가 영속성 컨텍스트에서 분리된 상태.
  • 삭제 (Removed): 엔터티가 삭제되어 더 이상 데이터베이스와 동기화되지 않는 상태.

5. 영속성 컨텍스트

영속성 컨텍스트는 JPA의 핵심적인 부분으로, "엔터티를 영구 저장하는 환경"을 의미합니다. 이 영역에서 엔터티는 데이터베이스와 동기화되며, 영속성 컨텍스트는 다음과 같은 특징과 구조를 가진다!예제도 같이 들어서 설명해보겠다.

1차 캐시:영속성 컨텍스트 내부에는 1차 캐시라는 메모리 영역이 존재하며, 여기에는 최근에 조회 또는 수정된 엔터티가 저장되는데, 이를 통해 반복적인 데이터베이스 접근을 줄여 성능을 향상시킬 수 있다.

User user1 = entityManager.find(User.class, 1L);
User user2 = entityManager.find(User.class, 1L);

위 코드에서 user1user2는 동일한 엔터티를 참조. 첫 번째 find 호출 시 데이터베이스에서 데이터를 가져와 1차 캐시에 저장하고, 두 번째 find 호출 시 1차 캐시의 데이터를 사용. 따라서, 두 번째 호출은 데이터베이스 접근 없이 캐시에서 정보를 가져오게 된다!

동일성 보장: 같은 트랜잭션 안에서 데이터를 조회할 때, 1차 캐시를 통해 항상 같은 인스턴스의 엔터티를 반환받게 되어 동일성이 보장.

boolean isEqual = user1 == user2;  // true

user1user2는 동일한 객체 인스턴스를 참조하므로 isEqualtrue를 반환합니다.

트랜잭션을 지원하는 쓰기 지연: 영속성 컨텍스트는 트랜잭션을 커밋하기 전까지 데이터베이스에 즉시 저장하지 않는다. 이를 통해 불필요한 데이터베이스 접근을 줄일 수 있다.

entityManager.getTransaction().begin();
User newUser = new User("이름");
entityManager.persist(newUser);
// 여기까지 데이터베이스에 저장되지 않음
entityManager.getTransaction().commit();  // 이 때 데이터베이스에 저장됨

persist 메서드 호출 시 실제 데이터베이스에 저장되지 않고, 트랜잭션 커밋 시에만 데이터베이스에 반영됩니다.

변경 감지: 영속성 컨텍스트는 관리 중인 엔터티의 변경 사항을 감지하며, 트랜잭션 커밋 시점에 이 변경 사항을 데이터베이스에 반영.

User user = entityManager.find(User.class, 1L);
user.setName("새 이름");  // 엔터티의 상태 변경
entityManager.getTransaction().commit();  // 변경 감지 후 데이터베이스에 이름 업데이트

지연 로딩: 연관된 엔터티가 실제로 사용될 때까지 데이터베이스에서 로딩을 지연시키는 방법. 이를 통해 성능을 최적화할 수 있다.

Order order = entityManager.find(Order.class, 1L);
List<Item> items = order.getItems();  // 실제로 데이터를 사용하는 시점

Order 엔터티에 연관된 Item 엔터티 목록은 getItems() 메서드를 호출할 때 실제로 데이터베이스에서 로딩된다. 이를 통해 불필요한 데이터 로딩을 최소화하고 성능을 최적화할 수 있다.

6. 플러시 (Flush)

플러시는 영속성 컨텍스트의 변경 내용을 데이터베이스에 동기화하는 작업이다. 이 작업은 영속성 컨텍스트에 있는 엔터티의 상태를 데이터베이스와 일치시키는 데 사용되는데. 그렇게 함으로써 데이터베이스의 현재 상태가 영속성 컨텍스트의 상태와 일치!!!

플러시는 다음의 경우에 발생:

1. 개발자가 직접 em.flush()를 호출할 때

User user = entityManager.find(User.class, 1L);
user.setName("변경된 이름");
entityManager.flush();  // 변경 내용을 데이터베이스에 즉시 반영

위의 예제에서 setName 메서드를 통해 엔터티의 상태가 변경되었다. flush 메서드를 호출하면 이 변경 사항이 데이터베이스에 즉시 반영된다.

2. 트랜잭션을 커밋할 때.

entityManager.getTransaction().begin();
User user = new User("새 사용자");
entityManager.persist(user);
entityManager.getTransaction().commit();  // 커밋 시 플러시가 자동으로 발생

트랜잭션을 커밋할 때, JPA는 자동으로 플러시를 호출하여 영속성 컨텍스트의 변경 내용을 데이터베이스에 반영합니다.

3. JPQL 쿼리를 실행할 때.

User user = entityManager.find(User.class, 1L);
user.setName("또 다른 이름");
List<User> users = entityManager.createQuery("SELECT u FROM User u", User.class).getResultList();  // JPQL 쿼리 실행 전 플러시 발생

JPQL 쿼리를 실행하기 전에 영속성 컨텍스트의 상태와 데이터베이스의 상태를 일치시키기 위해 플러시가 발생합니다.

요약: 플러시는 영속성 컨텍스트의 변경 내용을 데이터베이스에 동기화하는 중요한 작업이다. 이를 통해 영속성 컨텍스트와 데이터베이스 사이에 데이터의 일관성을 유지할 수 있다.

결론

JPA는 객체와 관계형 데이터베이스 간의 패러다임 불일치 문제를 해결하는 프레임워크로, 위의 개념들은 JPA를 효과적으로 사용하기 위해 반드시 이해하고 있어야 하는것이라는걸 알게 되었다. 이러한 개념들을 깊게 파악하고 실제 개발에 적용하면, 데이터베이스 연산을 더욱 효과적으로 처리할 수 있게 될꺼라는 생각을 하는 공부였다!!!

회고

오늘 JPA의 핵심 개념에 대해 깊게 다시 한 번 공부해볼 기회가 있었다. 사실 JPA를 사용하면서도 이런 핵심 개념들에 대해 얕게만 알고 지나갔던 부분들이 많았는데, 오늘 이렇게 상세하게 한 번 더 복습하면서 실질적으로 이해도가 높아진 것 같다.

특히, 엔터티의 생명 주기와 영속성 컨텍스트에 대한 부분이 가장 기억이 난다. 이전에는 단순히 객체를 데이터베이스에 저장하고 조회하는 도구로만 JPA를 생각했었는데, 실제로는 그 이상의 많은 기능과 최적화 기법이 숨어있음을 깨달았다. 이러한 내용을 알게 되면서, JPA를 사용할 때 어떻게 하면 더 효율적으로 데이터를 처리할 수 있을지에 대한 고민도 해보게 되었다.

또한, 플러시에 대한 부분도 깊게 이해할 수 있었다. 앞으로는 이러한 기본 개념을 바탕으로 JPA를 더욱 효과적으로 활용해보고, 다양한 최적화 기법에도 도전해보려고 한다.결과로는 앞으로의 개발에도 큰 도움이 될 것 같다.

profile
개발이란 무엇인가..를 공부하는 거북이의 성장일기 🐢

0개의 댓글