Notice
Recent Posts
Recent Comments
Link
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |
Tags
- QueryDSL
- AOP
- transaction
- Spring Boot
- jpa
- 스프링 핵심 원리
- kotlin
- springdatajpa
- 자바
- Proxy
- http
- 스프링 핵심 기능
- 그리디
- 인프런
- Greedy
- spring
- Servlet
- db
- 백준
- Android
- Exception
- JPQL
- Thymeleaf
- SpringBoot
- java
- 스프링
- pointcut
- 김영한
- 알고리즘
- JDBC
Archives
- Today
- Total
개발자되기 프로젝트
영속성 컨텍스트 2 본문
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
'인프런 > [인프런] 자바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