[JPA 기초 부수기] 영속성

CrackCo·2020년 10월 4일
0

JPA 기초 부수기

목록 보기
3/3
post-thumbnail

자바 서버 개발을 위한 JPA에 대해서 알아보고자 했다.
세 번째, 영속성에 대해서 알아보자.
학습 내용은 자바 ORM 표준 JPA 프로그래밍 교재를 기반으로 작성했다.

영속성 컨텍스트

영속성 컨텍스트는 JPA에서 주요 기능이라고 볼 수 있다. JPA가 데이터베이스에 접근하기 전 엔티티는 영속성 컨텍스트로 관리하며 commit이 수행되면 데이터베이스에 해당 내용을 전달한다. 영속성 컨텍스트는 엔티티 매니저를 생성할 때 생성되며 엔티티 매니저를 통해 관리할 수 있다.

엔티티 상태

  • 비영속(New/Transient) - 영속성 컨텍스트와 상관이 없는 상태
  • 영속(Managed) - 영속성 컨텍스트에 저장되어 있는 상태
  • 준영속(Detached) - 영속성 컨텍스트에서 분리된 상태
  • 삭제(Removed) - 삭제된 상태

비영속(New/Transient)

비영속 상태는 엔티티를 생성하기만 하고 영속성 컨텍스트에 저장하는 등의 동작을 수행하지 않은 상태이다.

// Member 객체 생성
Member member = new Member();
member.setId("id");
member.setUsername("CrackCo");

Member 객체인 member를 생성하고 값을 초기화 후 아무런 동작을 수행하지 않은 비영속 상태이다.

영속(Managed)

영속 상태는 EntityManager를 통해 영속성 컨텍스트에 저장한 상태이다. 해당 엔티티는 EntityManager에 의해 관리된다.

// 객체를 영속성 컨텍스트에 저장
em.persist(member);

memberEntityManager의 API persist()를 통해 영속성 컨텍스트에 저장되어 영속 상태이다.

기존에 persist() API는 데이터베이스에 저장한다고 하였지만 확실히 말하자면 영속성 컨텍스트에 저장하는 것이다.

준영속(Detached)

영속 상태였던 엔티티를 영속성 컨텍스트에서 분리하거나 영속성 컨텍스트가 초기화되면 해당 엔티티는 준영속 상태가 된다.

// 객체를 영속성 컨텍스트에서 분리
em.detach(member);

// 영속성 컨텍스트 초기화
em.clear();

memberEntityManager의 API detach()를 통해 영속성 컨텍스트에서 분리되어 준영속 상태이다.

삭제(Removed)

영속 상태인 객체를 영속성 컨텍스트와 데이터베이스에서 삭제한다.

em.remove(member);

memberEntityManager의 API remove()를 통해 영속성 컨텍스트에서 삭제되며 데이터베이스에서 삭제되는 SQL을 작성한다.

영속성 컨텍스트 관리

🚨 영속성 컨텍스트의 내용으로 데이터베이스에 접근할 때 엔티티는 @ID로 식별하기 때문에 엔티티 클래스를 정의할 때 반드시 지정해야 한다.

엔티티 조회

영속성 컨텍스트에서는 엔티티를 관리할 때 1차 캐시라는 공간에서 관리한다. EntityManagerfind() API를 호출하면 먼저 1차 캐시에서 엔티티를 찾아 반환하고 없으면 데이터베이스를 조회, 엔티티를 생성하여 1차 캐시에 저장하고 반환한다.

영속된 엔티티는 동일성을 보장한다.

Member a = em.find(Member.class, "member1");
Member b = em.find(Member.class, "member1");
System.out.println(a == b); // true

엔티티 등록

tx.begin(); // 트랜잭션 시작

// 영속성 컨텍스트에 저장
em.persist(memberA);
em.persist(memberB);

// 데이터베이스에 저장
tx.commit(); // 트랜잭션 커밋

엔티티 매니저는 트랜잭션에 커밋하기 전까지 영속성 컨텍스트 관리를 하며 해당 동작을 내부 쿼리 저장소INSERT SQL을 모아두고 트랜잭션의 commit() API를 수행하면 데이터베이스에 쿼리를 요청한다.

엔티티 수정

JPA에서 엔티티의 수정은 1차 캐시를 통해 수행된다.

tx.begin(); // 트랜잭션 시작

// member를 ID로 같고 있는 Member 엔티티 반환
Member member = em.find(Member.class, "member");

// 영속 엔티티 수정
member.setUsername("CrackCo1");
member.setAge(3);

tx.commit(); // 트랜잭션 커밋

위에서 작성했든 JPA는 영속성 컨텍스트를 통해 엔티티를 관리하는데 영속성 컨텍스트에 엔티티를 저장할 때 상태를 저장한다. 이를 스냅샷이라고 하는데 트랜잭션이 커밋되면 스냅샷과 현재 영속된 객체의 상태를 비교(변경 감지)하여 변경됐으면 내부 쿼리 저장소에 UPDATE SQL을 작성한다. 그 후 데이터베이스에 SQL을 보내고 데이터베이스의 트랜잭션을 커밋한다.

🚨 변경 감지는 영속 상태의 엔티티만 적용된다.

엔티티 삭제

Member memberA = em.find(Member.class, "memberA"); // 엔티티 조회
em.remove(memberA); // 엔티티 삭제

EntityManagerremove() API를 사용하여 해당 엔티티를 삭제하면 다른 동작과 같이 내부 쿼리 저장소에 DELETE SQL을 작성한다. 단, 영속성 컨텍스트에서는 즉시 삭제되기 때문에 엔티티를 수정하거나 할 때 주의해야 한다.

플러시

플러시는 영속성 컨텍스트의 변경 내용을 데이터베이스에 즉각 반영하는 EntityManger의 API이다. 트랜잭션의 commit() API를 수행하면 데이터베이스에 SQL이 전달된다고 하였는데 마지막에 EntityManagerflush() API가 자동으로 수행되어 데이터베이스에 전달되는 것이다.

JPQL 쿼리 실행 시에도 플러시는 자동 호출된다.

profile
개발이 좋아서 개발자가 됐다.

0개의 댓글