영속성 컨텍스트

번역하면 엔티티를 영구 저장하는 환경으로 논리적인 개념입니다.

엔티티 매니저에 의해 관리되며, DB와 애플리케이션 사이에서 엔티티의 일종의 저장소 같은 역할.

 

엔티티의 생명주기

  • 비영속(New/Transient)
    영속성 컨텍스트와 관계가 없는 상태.
  • 영속(Managed)
    영속성 컨텍스트에 저장된 상태
  • 준영속(Detached)
    영속성 컨텍스트에 저장되었다가 분리된 상태

  • 삭제(Removed)
    삭제된 상태

 

EntityManagerFactory emf = Persistence.createEntityManagerFactory("hello");
EntityManager em = emf.createEntityManager();

Member member = new Member();
member.setId(11L);
member.setName("Jack");
/* 여기까지는 비영속 */
em.persist(member); // 영속성 컨텍스트 관리 시작
em.clear(); // 준영속 상태로 영속성 컨텍스트 삭제
em.remove(member); // 비영속 상태로 영속성 컨텍스트와 DB 삭제

 

영속성 컨텍스트 관리의 장점

  • 1차 캐시
    영속성 컨텍스트에 저장해놓았다가 트랜잭션이 커밋되기 전까지 DB를 조회하지 않고 캐시에 있는 값을 조회합니다.
    비즈니스 로직이 매우 복잡할 경우 약간의 이득이 있을 수 있지만 트랜잭션 내에서 일어나므로 효과는 크지 않을 수 있습니다.

  • 동일성 보장
    같은 트랜잭션 안에서 엔티티의 비교의 == 연산자를 통해 비교할 수 있습니다.

  • 트랜잭션을 지원하는 쓰기 지연
    트랜잭션 커밋 전까지 INSERT SQL을 쓰기 SQL 저장소에 모았다가 전송할 수 있습니다.

  • 변경 감지
    엔티티를 수정하면 스냅샷과 비교하여 변경된 부분이 있는 경우
    업데이트 SQL을 쓰기 SQL 저장소에 저장했다가 트랜잭션 커밋 시 DB에 전송합니다.

플러시

플러시는 영속성 컨텍스트의 변경 내용을 데이터베이스에 반영.

영속성 컨텍스트의 내용들을 DB와 동기화한다고 이해하면 됩니다.

이름 때문에 오해할 수 있지만 삭제하거나 비우는 작업이 아닙니다.

 

스냅샷과 비교해서 수정된 엔티티를 찾고, 수정된 엔티티에 대해 쿼리를 생성하여 쓰기 지연 SQL 저장소에 등록합니다.
쓰기 지연 SQL 저장소의 쿼리를 데이터베이스에 전송합니다.

 

플러시 하는 경우

  • flush() 메소드 명시적 호출.
  • 트랙잭션 커밋할 경우
  • JPQL 쿼리 실행할 경우

참고

자바 ORM 표준 JPA 프로그래밍 / 김영한 저자

'Java > JPA' 카테고리의 다른 글

JPA (Java Persisitence API) - JPA 소개 (1)  (0) 2022.03.21

1. 소개

JAVA 진영의 ORM 표준.

스프링 기반의 실무에서는 Spring Data JPA를 주로 사용하여 개발하며 Hibernate 구현체를 대부분 많이 사용합니다.

JPA, Spring Data JPA, Hibernate 관계에 대해 조금 쉽게 설명하면 Hibernate는 JPA 구현체이고

Spring Data JPA는 Spring 프레임워크에서 JPA를 다루기 쉽게 구현된 것이라 생각하면 됩니다.

Spring Data JPA는 Hibernate만을 구현체로 사용하지 않고 여러 다른 구현체를 선택할 수 있습니다.

하지만 대부분 Hibernate를 구현체로 사용하고 있기때문에

이런 관계에 대해서 많이 혼동이 있는 분들이 많은 것 같습니다.

JPA, Spring Data JPA, Hibernate 가 혼동된다면 아래 이미지를 보며 어느 정도 관계에 대해서 이해가 쉬울 것 같습니다.

 

 

2. ORM(Object-relational mapping) 

객체와 관계형 데이터베이스를 맵핑하는 기술.

객체는 객체대로 설계하고 RDBMS는 RDBMS대로 설계하고 ORM 프레임워크가 중간에서 맵핑.

 

3. 기존 SQL 중심 개발의 문제점

public Class User {
	private String userId;
    private String userName;
    private String email;
    private UserGroup userGroup;
}
public Class UserGroup {
	private String groupId;
    private String name;
}

두 개의 참조 관계의 객체들이 있다면 조인하여 데이터를 얻을 수 있는

SQL을 조회 개발이 필요하고 SQL문의 조회 결과를 각각의 두 개의 객체에 결과를 다음과 같이 맵핑해줘야 합니다.

SELECT U.*, UG.*
  FROM USER U JOIN USER_GROUP UG ON U.groupId = UG.groupId
public User findUser(String userId) {
	// SQL 실행 결과를 아래의 객체에 세팅
    User user  = new User();
    user.setUserName(name);
    		...
    UserGroup userGroup = new UserGroup();
    user.setGroupName(name);
    		...
    // 회원과 그룹의 관계 세팅
    user.setUserGroup(userGroup);
    return user;
}

 

 

이런 맵핑 작업이 계속 필요하기 때문에 생산성이 떨어지다 보니 하나의 객체로 처리할 수 있게 DTO를 만들어서

조회 결과에 대해 setter/getter 처리하는 경우 많습니다.

그런데 이런 경우 SQL 문에 SELECT 필드에 따라서 데이터가 있을 수도 없을 수도 있는 경우가 발생하게 됩니다.

그러다 보니 일반적으로 MVC model을 사용하여 계층적으로 분리를 많이 하지만 논리적으로는 얽혀있는 상태가 되면서

SQL 문까지 전부 확인하기 전까지는 슈퍼 DTO(객체)의 데이터가 없어서 안 들어간 것인지 필요가 없어서 뺀 것인지

신뢰하기 어렵기 때문에 여기서 또 개발에 생산성과 유지보수가 점점 어려워지게 됩니다

문제는 객체지향 모델링할수록 이런 맵핑 작업이 늘어나게 되고

그러다 보니 SQL 문에 맞춰서 객체를 설계하는 경우가 많아지게 되면서 생산성은 떨어지게 되는 악순환이 반복됩니다.

또 다른 경우를 확인해보면 예를 들어 어떤 기능을 개발한다고 가정하면 관련 CRUD SQL에 생성이 필요하고

이렇게 생성한 상태에서 DB 테이블에 칼럼 하나가 추가된다고 하면 관련된 SQL 문 모두 수정 필요합니다.

번거롭고 생산성이 떨어지는데 혹시 실수로 하나라도 추가나 수정해야 할 필드를 SQL문에서

놓치게 되면 에러가 발생하게 됩니다.

 

4. JPA를 활용한 해결

이런 문제들에 대해서는 JPA는 솔루션이될 수 있습니다.

별도의 SQL 문 작성 없이 객체 관계 설정을 통해 SQL 문을 생성해주므로 단순히 JPA에 정의한 CRUD 메서드를 

사용하여 생산성을 높일 수 있습니다.

지연 로딩 기능을 활용해 조인 관계 놓인 객체 데이터라고 해도 객체가 조회되는 시점에 SQL을 생성/조회할 수 있고

만약 항시 채워진 데이터가 필요할 경우 옵션 설정을 통한 즉시 로딩 기능으로 데이터를 모두 하나의 SQL을 생성/조회할 수 있습니다.  이런 기능을 활용하여 맵핑을 위한 복잡한 추가 코딩을 줄일 수 있습니다.

모든 부분이 직접적인 SQL 작성 없이 처리할 수 없는 경우를 처리하기 위한 SQL과 유사한 JPQL를 사용하여 조회할 수 있게 만든 기능도 있습니다.

 

5. 마치며

간단하게 개념과 기존 SQL 중심 개발의 문제점과 JPA에 어떤 해결방법이 있는지 확인해보았습니다.

다음 글에서는 영속적 콘텍스트와 4번 항목에서 말한 지연 로딩 같은 솔루션에 대한 예제를 살펴보겠습니다.

 

※ 참고

https://docs.jboss.org/hibernate/orm/5.4/userguide/html_single/Hibernate_User_Guide.html

https://suhwan.dev/2019/02/24/jpa-vs-hibernate-vs-spring-data-jpa/ 

자바 ORM 표준 JPA 프로그래밍 / 김영한 저자

'Java > JPA' 카테고리의 다른 글

JPA (Java Persisitence API) - JPA 영속성 관리 (2)  (0) 2022.05.17

+ Recent posts