병아리의 코딩 일기

[JPA] 영속성 컨텍스트의 이점 본문

자바 Java/Spring

[JPA] 영속성 컨텍스트의 이점

oilater 2023. 2. 15. 12:03

저번 시간에는 영속성 컨텍스트란 무엇인지에 대해 알아보았다.

이번엔 '영속성 컨텍스트가 가진 이점'에 대해 알아보자!

 

1. 1차 캐시에서 조회한다.

Member member = new Member();
member.setId("member1");
member.setName("회원1");

//1차 캐시에 저장됨
em.persist(member);

//1차 캐시에서 조회
Member findMember = em.find(Member.class, "member1");

멤버 객체를 만들고 영속성 컨텍스트에 담으면 @Id : "membrer1"를 Key , Entity : Member 를 으로 하는 1차 캐시가 생성된다.

그래서 findMember를 할 때 1차 캐시에서 조회한다. 즉, 실행해보면 select 쿼리가 따로 안나간다!

 

member findMember2 = em.find(Member.class, "member2");

여기서 만약 Member2를 찾고 싶으면 방금 시나리오에서 1차 캐시에 없었기 때문에 DB에서 조회한다.

 

 

Member findMember = em.find(Member.class, 101L);
Member findMember2 = em.find(Member.class, 101L);

이렇게 하면 쿼리가 한번만 나간다. 두번째 findMember2 는 1차 캐시에서 조회하기 때문이다. 비즈니스가 정말 복잡할 때는 도움이 될 수도 있다. 성능적인 이점보다는 컨셉을 이해할 때 주는 이점이 있다.

 

* 데이터 베이스 한 트랜젝션 안에서만 효과가 있기에 그렇게 큰 성능의 이점을 가지고 있진 않다.

 

 

 
System.out.println("result =" + (findMember == findMember2));

또한 JPA는 영속 엔티티의 동일성을 보장해준다. 

결과 : result =true  

 

 

2. 트랜잭션을 지원하는 쓰기지연

em.persist(memberA);
em.persist(memberB);

여기까진 INSERT SQL을 데이터베이스에 보내지않는다.

em.persist(memberA);
em.persist(memberB);

tx.commit();

트랜잭션을 커밋하는 순간 INSERT SQL을 데이터베이스에 보낸다.

 

영속성 컨텍스트에는 쓰기지연 SQL 저장소라는 재미난 것이 있다. 

em.persist(member)를 하면 JPA가 엔티티를 분석을 해서 INSERT쿼리를 생성하고 쓰기 지연 SQL 저장소에 넣어두는 것이다.

A, B 둘다 쌓여있는 상태에서 transaction을 커밋하는 순간 flush가 되면서 날라가고 실제 DB 트렌젝션이 커밋된다.

 

Member member1 = new Member(150L, "A");
Member member2 = new Member(160L, "B");

em.persist(member1);
em.persist(member2);
System.out.println("===================");

tx.commit();

결과를 보면 "========"이후 tx.commit(); 이 실행된 시점에서 쿼리가 나가는 것을 볼 수 있다!

 

 

3. 엔티티 수정 (변경감지 - Dirty Checking)

Member member = em.find(Member.class, 150L);
member.setName("ZZZZZ");

이후에 따로 persist를 해줄 필요가 없다.

JPA 목적은 자바 컬렉션 다루듯이 객체를 다루는 것이다.

자바 컬렉션에서 값을 꺼내서 변경하면 그걸 다시 컬렉션에 집어넣는가? 아니다.

오히려 em.persist(member); 라는 코드를 쓰면 안된다.

 

실행 결과를 보면 마법 같이 자동으로 update 쿼리가 나간 것을 볼 수 있다.

이 비밀은 영속성 컨텍스트 안에 다 있다.

 

JPA는 tx.commit 시점에 내부적으로 flush() 라는 것이 호출된다.

이때 엔티티와 스냅샷을 비교하는데,

1차 캐시에는 Id, Entity, 스냅샷 이라는 것이 있다.

내가 값을 읽어온 그 최초 시점에 스냅샷으로 떠놓고 member의 값을 변경하면 commit되는 시점에 값을 비교해서 바뀌었으면 update쿼리를 쓰기 지연 SQL 저장소에 만들어놓고, 이걸 데이터베이스에 반영하고 커밋한다.

 

 

그러니까 이런식으로 코드를 짜면 안된다. em.update(member); 를 안 써도 이미 JPA에서는 update 쿼리가 날라간다.

Member member = em.find(Member.class, "memberA");
member.setName("ZZZZZ");

if(member.getName().equals("ZZZZZ")) {
    em.update(member);
}

 

4. 엔티티 삭제

Member memberA = em.find(Member.class, "memberA");
em.remove(memberA);

엔티티를 찾아와서 remove 하면 삭제가 된다. 방금의 메커니즘과 똑같고 트랜젝션 커밋 시점에 delete 쿼리가 나간다.

 


여기까지 영속성 컨텍스트의 이점에 대해 알아보았다. 

728x90
반응형
LIST

'자바 Java > Spring' 카테고리의 다른 글

[JPA]플러시  (0) 2023.02.15
[JPA] 영속성 컨텍스트란?  (0) 2023.02.15
JPA 구동 방식  (0) 2023.02.15