JPA에서 가장중요한건 2가지
- 객체와 관계형 DB 매핑
- 영속성 컨텍스트(JPA 내부동작이 영속성 컨텍스트와 연관되있다.)
영속성 컨텍스트란?
- 논리적인 개념으로 눈에 보이지않는다.
- Enitity를 영구 저장하는 환경.
- em.persist(entity); DB에 저장한다보단 영속성 컨텍스트라는곳에 저장한다.
- Entity Manager를 통해 영속성 컨텍스트에 접근한다.
엔티티의 생명주기
- 비영속(new): 영속성 컨텍스트와 전혀상관없는 새로운 상태
// 객체만 생성한 상태(비영속)
Member member = new Member();
member.setId("member1");
member.setUsername("회원1");
- 영속: 영속성 컨텍스트에 관리되는 상태
EntityManager em = emf.createEntityManger();
Transaction tx = em.getTransaction()
tx.begin();
// 객체를 저장한 상태(영속)
em.persist(member)
- 준영속: 영속성 컨텍스트에 저장되었다가 분리된 상태
em.detach(member)
- 삭제 : 삭제된 상태
em.remove(member);
영속성 컨텍스트의 이점
1. 1차캐시(엔티티 조회)
em.persist(member)를 하게되면
영속성 컥텐스트 내부에 1차 캐시가 존재하는데. 1차 캐시에 id-entity가 key-value 형태로 저장한다.
이떄
Member findMember = em.find(Member.class, "member1");를 하면 1차 캐시에서 조회가 이루어진다.
그런데 여기서 member1대신에 member2를 조회하면 1차 캐시에 없으므로 DB에서 조회한다.
Member findMember = em.find(Member.class, "member2");
DB 트랜잭션이 끝나면 영속성 컨텍스트를 제거한다.(즉, 1차 캐시도 지워진다.)
애플리케이션 전체에서 공유하는것은 2차 캐시
하나의 트랜잭션 안에서의 공유는 1차 캐시
2.영속 엔티티의 동일성 보장
Member a = em.find(Member.class, "member1")
Member b= em.find(Member.class, "member2")
a==b // 동일성 비교 true
같은 트랙잭션안에서 1차 캐시로 인해 동일성 보장.
3. 트랜잭션을 지원하는 쓰기 지원
transaction.begin();
em.persist(memberA);
em.persist(memberB);
//여기까지 insert sql을 db에 보내지않음.
transaction.commit() // 커밋하는순간 DB에 insert sql을 보낸다.
쓰기지연 SQL 저장소란게 존재하는데
persist(memberA) 를 하면 1차캐시에 저장되는것과 동시에 insert SQl를 생성하고
쓰기지원 SQL 저장소에 저장한다.
이를 transaction.commit()을 하게되면 쓰기지연 sql 저장소에 있는것들이 flush가 된다.
persist할떄 바로 쿼리를 안날리므로 버퍼링같은 기능(모았다가 한번에 보내는기능)을 줄수있다.
batch_size를 두어서 한번에 쿼리문을 보낼수있다.(성능상 이점이있다.)
4. 변경 감지(엔티티 수정)
Member memberA = em.find(Member.class, "memberA");
memberA.setUsername("hi");
// em.update(member)같은 이런코드가 있어야하지않나?
최초의 상태를 스냅샷으로 찍어둔다.
transaction.commit() 하게되면 내부적으로 flush가 된다.
그다음 엔티티 와 스냅샷 비교한다.
그떄 다른게잇으면 Update Sql를 생성하고 Db에 flush가 된다.
엔티티 삭제는 호출시점에 삭제됨.
em.remove(MemberA)
5. 지연로딩
플러시란?
정의: 영속성 컨텍스트의 변경내용을 DB에 반영(영속성 컨텍스트의 변경내용을 DB에 동기화)
플러시 발생
변경 감지 -> 수정된 엔티티를 쓰기지연 SQL 저장소에 등록 -> 쓰기지연 SQL 저장소의 쿼리를 DB에 전송
영속성 컨텍스트를 플러시하는방법
- em.flush() - 직접 호출
이렇게 직접 호출하면 즉시 쿼리가 날라가서 DB에 반영
- 트랜잭션커밋 - 플러시 자동 호출
트랜잭션이라는 작업 단위가 중요해서 커밋직전에 flush 가되게 만들어져있음.
- JPQL쿼리 실행시 - 플러시 자동호출
em.persist(memberA);
em.persist(memberB);
// 이떄 쿼리가 안날라가
// JPQL 실행 : 이떄 자동으로 플러시가 된다. (조회를 해야하는데 DB에 반영내용 적용하려고)
query = em.createQuery("select m from Member m", Member.class);
List<Member> members = query.getResultList();
준영속상태
em.detach(member) // 특정 엔티티만 준영속 상태로 전환
em.clear() // 영속성 컨텍스트를 완전히 초기화
em.close() // 영속성 컨텍스트 종료
'𝗦𝗣𝗥𝗜𝗡𝗚 > 𝐎𝗥𝗠-𝗝𝗣𝐀' 카테고리의 다른 글
고급 매핑 (1) | 2024.01.03 |
---|---|
다양한 연관관계 매핑 (0) | 2024.01.03 |
연관관계 매핑 기초 (0) | 2024.01.03 |
엔티티 매핑 (0) | 2024.01.02 |
JPA 구동방식 (0) | 2023.12.27 |