Notice
Recent Posts
Recent Comments
Link
«   2024/11   »
1 2
3 4 5 6 7 8 9
10 11 12 13 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28 29 30
Archives
Today
Total
관리 메뉴

개발자되기 프로젝트

영속성 컨텍스트 2 본문

인프런/[인프런] 자바ORM 표준 JPA 프로그래밍

영속성 컨텍스트 2

Seung__ 2021. 8. 8. 22:34

1. 엔티티조회, 1차 캐시


  • 영속 상태는 1차 캐시에 올라가 있는 상태, persist, find로 1캐시에 들어간 상태.
  • 영속성 컨텍스트 내부에는 "1차 캐시"가 있음
  • persist(entity)할 경우 1차 캐시에 저장됨.
    //엔티티를 생성한 상태(비영속) 
    Member member = new Member(); 
    member.setId("member1"); 
    member.setUsername("회원1");
    //엔티티를 영속 
    em.persist(member);​
  • @Id(PK)와 @Entity(객체)가 key & value로 1차캐시에 저장됨.
  • 1차 캐시에서 id로 조회하는 경우
Member member = new Member();
member.setId("member1");
member.setUsername("회원1");
//1차 캐시에 저장됨
em.persist(member);
//1차 캐시에서 조회
Member findMember = em.find(Member.class, "member1");

- em.find()를 시도하면 영속성 컨텍스트의 1차 캐시에서 먼저 찾음.


- 만약 1차 캐시에 있으면 반환, 1차 캐시에 없으면 DB 조회 및 1차캐시에 저장함.

  • 실제 큰 도움은 안됨. ㅋㅋㅋㅋ
  • em은 database Transaction 단위로 만듦. database Transaction 종료 시에 같이 종료됨.
  • 고객 요청이 들어와서 비즈니스가 끝나면 영속성 컨텍스트 지움. 즉 1차 캐시도 날라감
  • 1차캐시는 db의 transaction내에서만 이득임. 
  • persist 후 조회
    - persist후  조회시 select쿼리가 실행되지 않았다. DB에 접근하지 않고 1차 캐시에서 조회하기 때문ㅇ
    //비 영속상태, 객체 생성한 상태
    Member member = new Member();
    member.setId(101L);
    member.setName("CCC");
    
    //영속상태
    em.persist(member);
    
    //조회
    System.out.println("select 쿼리가 실행될까??");
    Member findMember = em.find(Member.class, 101L);
    System.out.println("findMember.id= " + findMember.getId());
    System.out.println("findMember.name = " + findMember.getName());

    - insert쿼리는 commit에 의해 실행됨.
    select 쿼리가 실행될까??
    findMember.id= 101
    findMember.name = CCC
    
    Hibernate: 
        /* insert hellojpa.Member
            */ insert 
            into
                Member
                (name, id) 
            values
                (?, ?)
  • 영속성 컨텍스트 새로 생성 후 2번 조회
    - DB에 엔티티가 저장된 상태에서
    - 영속성 컨텍스트를 띄우고 바로 조회해보자.
    - 영속성 컨텍스트가 새로 시작되었으니 1차 캐시는 비어있을 것.
    - 따라서 같은 entity를 두 번 조회하면  select 쿼리는 한 번만 나갈 것.
   public static void main(String[] args) {
        EntityManagerFactory emf = Persistence.createEntityManagerFactory("hello");

        EntityManager em = emf.createEntityManager();

        EntityTransaction tx = em.getTransaction();
        tx.begin();

        try{

            System.out.println("select 쿼리가 실행될까??");
            Member findMember1 = em.find(Member.class, 101L);
            Member findMember2 = em.find(Member.class, 101L);


            tx.commit();
        }catch (Exception e){
            tx.rollback();
        }finally {
            em.close();
        }

        emf.close();

    }

    - select쿼리가  한 번 만 실행되었다.

Hibernate: 
    select
        member0_.id as id1_0_0_,
        member0_.name as name2_0_0_ 
    from
        Member member0_ 
    where
        member0_.id=?
  • JPA는 엔티티를 조회하면 1차캐시에 올린다.

 

2. 영속 엔티티의 동일성 보장.


  • 1차 캐시로 반복 간으한 읽기 등급의 트랜잭션 격리 수준을 데이터베이스가 아닌
    애플리케이션 차원에서 제공
  • JPA가 영속엔티티의 동일성을 보장.
  • 같은 tranaction내에서 식별자(PK)가 같으면 동일객체로 봄.
  • 1차 캐시가 있어서 가능함. id로 1차 캐시에서 조회하기 때문
Member findMember1 = em.find(Member.class, 101L);
Member findMember2 = em.find(Member.class, 101L);

boolean result = findMember1 == findMember2;
System.out.println("result = " + result);
result = true

 

3. 엔티티 등록할 때 transaction을 지원하는 쓰기 지연


  • persist해도 바로 insert 쿼리를 바로 날리지않음
  • 즉 persist해도 DB에 반영되는 것이 아니라 SQL을 생성해서 쓰지지연 SQL저장소에 넣어둠.
    - entity는 1차캐시에 올라감.
  • commit하는 순간 DB에 만들어둔 insert SQL 보냄.
  • 별도로 flush하면 원하는 시점에 DB반영 가능.
EntityManager em = emf.createEntityManager();
EntityTransaction transaction = em.getTransaction();
//엔티티 매니저는 데이터 변경시 트랜잭션을 시작해야 한다.
transaction.begin(); // [트랜잭션] 시작
em.persist(memberA);
em.persist(memberB);
//여기까지 INSERT SQL을 데이터베이스에 보내지 않는다.
//커밋하는 순간 데이터베이스에 INSERT SQL을 보낸다.
transaction.commit(); // [트랜잭션] 커밋

  • test
Member member1 = new Member(200L, "JPA");
Member member2 = new Member(201L, "SPRING");

em.persist(member1); //영속성 컨텍스트에 entity, query쌓아둠.
em.persist(member2);
System.out.println("================================");

tx.commit(); //commit하는 시점에 쿼리 날라감.
================================
Hibernate: 
    /* insert hellojpa.Member
        */ insert 
        into
            Member
            (name, id) 
        values
            (?, ?)
Hibernate: 
    /* insert hellojpa.Member
        */ insert 
        into
            Member
            (name, id) 
        values
            (?, ?)
  • 왜이렇게함???
    - persist마다 쿠리 나가면 최적화 여지가 없음.ㅜㅜ
    - 모아서 한번에 DB에 날릴 수 있음.

 

 

4. 엔티티 수정, 변경감지, dirty checking


  • 현재 DB에 id 200인 엔티티의 name은JPA다 요놈을 수정해보자.
try{

  Member findMember = em.find(Member.class, 200L);
  findMember.setName("changed");

  //em.persist(findMember); 필요없음~~~
  tx.commit(); //commit하는 시점에 쿼리 날라감.
}
  • 와! 값을 바꾸기만 했는데 update 쿼리 나감!!!
Hibernate: 
    /* update
        hellojpa.Member */ update
            Member 
        set
            name=? 
        where
            id=?

와! 바뀜!!!

  • JPA는 변경감지(dirty checking)을 통해 영속상태 엔티티의 값을 변경할 수 있도록 지원함.
  • 어케하는건데~~~
    - tx.commit 시점에 flush호출됨.
    - entity와 스냅샷을 비교함.
    - 스냅샷은 영속성 컨텍스트에 최초로 들어온 상태를 저장.
    - flush가 호출되면 JPA가 commit 시점의 entity와 이전에 만들어진 스냅샷을 비교
    - 변경된 부분이 있으면 Update SQL을 생성해서 쓰기지연 SQL저장소에 넣어둠.
    - Update 쿼리 DB 로 보냄.
    - 즉, 1차캐시의 스냅샷과 비교하기 우해서는 해당 엔티티는 영속성 컨텍스트에 올라가있는
      영속상태여야 dirty checking 대상이 된다.
    - 같은 이유로 어떤 새로운 객체를 만들고 영속 엔티티의 PK와 필드값들을 넣더라고,
      해당 엔티티는 영속성 컨텍스트에 들어간 적이 없기 때문에 스냅샷이 없고ㅡ
      따라서 dirty checking의 대상이 안된다. 비교할 대상이 없기 때문
      이 경우는 merge를 통해 데이터를 덮어써야 한다.

5. 엔티티 삭제


  • remove를 하면 delete SQL이 쓰기지연 SQL저장소에 올라가고
  • commit 시점에 만들어둔 SQL이 DB로 나감.
//삭제 대상 엔티티 조회
Member memberA = em.find(Member.class, “memberA");
em.remove(memberA); //엔티티 삭제

 

6. GitHub : 210808 Persistence Context


 

GitHub - bsh6463/JPA

Contribute to bsh6463/JPA development by creating an account on GitHub.

github.com

 

'인프런 > [인프런] 자바ORM 표준 JPA 프로그래밍' 카테고리의 다른 글

객체와 테이블 매핑  (0) 2021.08.08
플러시, 준영속 상태, 정리  (0) 2021.08.08
영속성 컨텍스트  (0) 2021.08.08
Hello JPA  (0) 2021.08.08
JPA 시작, 프로젝트 세팅  (0) 2021.08.07
Comments