어 나 갱수.

[JPA] JPA 영속성 컨텍스트 🤫 본문

Spring

[JPA] JPA 영속성 컨텍스트 🤫

김경수 2023. 12. 3. 12:01
728x90

영속성 컨텍스트란 

영속성 컨텍스트는 엔티티를 영구 저장하는 환경이라는 뜻입니다. 애플리케이션과 데이터베이스 사이에서 엔티티를 저장하는 가상 데이터베이스와 같은 역할을 한다. 

엔티티의 생명주기

비영속

영속성 컨텍스트에서 비영속 상태란 영속성 컨텍스트와 관련이 없는 상태를 말합니다.

아래의 코드와 같이 객체를 생성만 하고 영속성 컨텍스트에 저장하지 않는 상태를 말합니다.

//객체를 생성한 상태(비영속)
Member member = new Member();
member.setId("member1");
member.setUsername("회원1");

영속

영속성 컨텍스트에서 영속 상태란 영속성 컨텍스트에 객체가 저장된 상태를 말합니다.

아래의 코드와 같이 객체를 생성하고 EntityManager를 생성하고 객체를 저장한 상태를 말합니다.

//객체를 생성한 상태(비영속)
Member member = new Member();
member.setId("member1");
member.setUsername(“회원1”);
EntityManager em = emf.createEntityManager();
em.getTransaction().begin();
//객체를 저장한 상태(영속)
em.persist(member);

준영속

영속성 컨텍스트에서 준영속 상태란 영속성 컨텍스트에 객체가 저장되었다고 분리된 상태를 말합니다.

아래의 코드와 같이 detach함수로 영속성 컨텍스트에서 분리된 상태를 말합니다.

//회원 엔티티를 영속성 컨텍스트에서 분리, 준영속 상태
em.detach(member);

삭제

영속성 컨텍스트에서 삭제 상태란 영속성 컨텍스트에서 객체가 삭제된 상태를 말합니다.

//객체를 삭제한 상태(삭제)
em.remove(member);

영속성 컨텍스트의 장점

1차 캐시

영속성 컨텍스트 내부에는 1차 캐시가 존재합니다. 1차 캐시란 영속성을 이용해서 DB에서 데이터를 가져오지 않고, 영속성 컨텍스트라는 곳에 저장해 같은 엔티티를 조회한다면 DB가 아닌 영속성 컨텍스트에서 조회를 해서 성능적으로 이점을 가져올 수 있습니다. 

말 그대로 영속성 컨텍스트에서 캐시 기능을 할 수 있는 것입니다.

 

동일성 보장

Member a = em.find(Member.class, "member1");
Member b = em.find(Member.class, "member1");

System.out.println(a==b) // true

 

1차 캐시로 반복적인 작업이 캐시에서 이루어져서 1차 캐시로 반복 가능한 읽기 등급의 트랜잭션 격리 수준을 데이터베이스가 아닌 애플리케이션 차원에서 제공합니다.

 

쓰기 지연

EntityManager em = emf.createEntityManager();
EntityTransaction transaction = em.getTransaction();
//엔티티 매니저는 데이터 변경시 트랜잭션을 시작해야 한다.
transaction.begin(); // [트랜잭션] 시작

em.persist(memberA);
em.persist(memberB);
//여기까지 INSERT SQL을 데이터베이스에 보내지 않는다.

//커밋하는 순간 데이터베이스에 INSERT SQL을 보낸다.
transaction.commit(); // [트랜잭션] 커밋

 

em.persist()로 객체를 영속성 컨텍스트에 저장해도 DB에 바로 Insert 쿼리를 날리지 않는다. 

SQL 쿼리들을 모아놓았다가 flush 될 때(영속성 컨텍스트의 변경내용을 DB에 반영할 때) 모아둔 쿼리를 모두 날린다.

이를 쓰기 지연이라고 한다.

 

변경 감지

EntityManager em = emf.createEntityManager();
EntityTransaction transaction = em.getTransaction();
transaction.begin(); // [트랜잭션] 시작

// 영속 엔티티 조회
Member memberA = em.find(Member.class, "memberA");

// 영속 엔티티 데이터 수정
memberA.setUsername("hi");
memberA.setAge(10);

//em.update(member) 이런 코드가 있어야 하지 않을까?

transaction.commit(); // [트랜잭션] 커밋

 

영속성 컨텍스트에서 엔티티를 조회하고 그 엔티티를 수정한다고 해보자

조회한 엔티티의 데이터를 수정했으면 수정한 엔티티를 영속성 컨텍스트에서도 수정하는 코드가 있어야 할 거 같은데 영속성 컨텍스트에서는 그럴 필요가 없다.

 

JPA에서는 커밋을 하게 되면 스냅샷과 엔티티를 비교합니다.

여기서 스냅샷이란 값을 읽어온 최초의 상태를 스냅샷이라고 합니다. 만약 스냅샷과 커밋한 이후의 엔티티의 데이터가 다르면 

update 쿼리문을 쓰기 지연 sql 저장소의 저장한 후 update 쿼리를 DB에 전달하게 된다.

728x90