JPA03. 엔터티 생명주기
포스트
취소

JPA03. 엔터티 생명주기

Transient (비영속 상태)

jpa랑 관련없음.

1
2
3
Account account = new Account();
account.setUsesrname("keesun2");
account.setPassword("jpa");

 

Persistent (영속 상태)

영속성 컨텍스트에 저장된 상태

1
2
3
4
5
Session session = entityManager.unwrap(Session.class);
session.save(account);

Account keesun = session.load(Account.class, account.getId()); // SELECT 쿼리가 발생하지 않음. 캐시된 것이 있기 때문에 DB로 요청안해도됨.
keesun.setUsername("whiteship"); // dirtyChecking, write봐인딩?

일반 SQL로 했으면 위의 작업은 다음고 ㅏ같이 이루어짐.

  1. INSERT
  2. SELECT
  3. UPDATE

하지만 실제로는 2가지만 이루어짐.

  1. INSERT
  2. UPDATE
1
2
3
4
5
6
7
INSERT INTO account
    (password, username, id) VALUES
    (?, ?, ?)

UPDATE account
SET password=?, username=?
WHERE id=?    

=> SELECT 쿼리가 일어나지 않았음. Persistent 상태에 있는 객체의 장점임.

 

1
2
3
4
5
6
Session session = entityManager.unwrap(Session.class);
session.save(account);

Account keesun = session.load(Account.class, account.getId()); // SELECT 쿼리가 발생하지 않음. 캐시된 것이 있기 때문에 DB로 요청안해도됨.
keesun.setUsername("whiteship"); // dirtyChecking, write behind
keesun.setUsername("keesun2");
  1. INSERT
1
2
3
INSERT INTO account
    (password, username, id) VALUES
    (?, ?, ?)

keesun2 이름이 같으므로 update 쿼리를 하지 않음.

dirtyChecking : 객체의 변경사항을 계속 감지하는 것 write behind : 객체 상태를 DB에 최대한 늦게 반영하는 것

Removed (삭제)

실제 커밋이 일어날 때 삭제가 일어남.

Detatch 준영속 상태

   

  • 1차캐시
  • 동일성 보장
  • 트랜잭션을 지원하는 쓰기 지연 (write-behind)
  • 변경 감지 (Dirty Checking)
  • 지연 로딩(Lazy Loading)

1차캐시

영속성콘텍스트가 new에서 생성되거 없어질 때까지 잠깐 존재하는녀석

1
2
3
4
5
6
Member member = new Member();
member.setId("member1");
member.setUsername("회원1");

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

1차 캐시 |@id |Entity| |”member1”| member1|

// DB에 요청하기 전에 1차 캐시에서 조회

1
Member findMember = em.find(Member.class, "member1");

트래픽 100명이 온다 -> 영속 컨텍스트 100개 생기고, 캐시 100개 생김. 나가면 다 없어짐. ㅇㅋ? 서로 공유하지 않는 캐시. 트랜잭션 시작하고 끝날때까지만 유짛는 굉장이 짧은 캐시.

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

1차 캐시 |@id |Entity| |”member1”| member1| |”member2”| member2|

와 영한씨 개꿀인데 강의…

동일성 보장

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

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

반복가능한 읽기 등급의 트랜잭션 격리 수준을 DB가 아닌 애플리케이션 차원에서 제공 (1차 캐시)

쓰기 지연

commit 하면 sql보냄.

em.

1
2
// 쓰기 지연 SQL 저장소에 있는 쿼리 보내기 (1차 캐시 지우는 것이 아님.)
em.flush();
1
2
// flush + commit
tx.commit();

 

1
2
3
4
5
Member a = em.find(Member.class, "member1");

// Update
a.setUsername("Hi");
a.setAge(12);

jpa는 트랜잭션 commit 되는 시점에 1차캐시 넣을 때 스냅샷…을 떠놓음

flush 하는 시점에 다 비교함. 바뀐놈 있으면 업데이트 쿼리 만들어서 db에 보냄. 이렇게 값만 바꿔도

사실 1차캐시에 저장할 때 스냅샷을 뜸.

1차 캐시 |@id |Entity|스냅샷| |”member1”| member1|member1 스냅샷| |”member2”| member2|member1 스냅샷|

Entity랑 스냅샷이 다른게 있으면 Update쿼리를 만듬.

변경감지 (더티 체킹)

영속성 컨텍스트에 관리되는 애들은 뭐가 변경되있는지 다 알아요.

나이 하나만 바꿔도 다 알아요

그래서 커밋하거나 플러쉬할 때 업데이트 쿼리를 DB에 날려버립니다.

왜 이렇게 동작할까요>? em.update를 만들지!!

사상때무에 그럼. 우리가 자바 컬렋

1
2
3
4
5
6
List<User> users = new ArrayList<>();
users.add(user1);
users.add(user2);
users.add(user3);

user2.setAge("10");

컬렉션에 있는 내용이 변경되면 알아서 컬렉션에 반영되잖아. 자바의 이런 패러다임을 따른거지..

마치 자바 컬렉션에 있는 객체 다루듯이!!!! 갸꿀

플러시

플러시 일어나면 스냅샷 다 비교하고.. UPDATE쿼리 만들고 DB에 다보내버려~

FLUSH발생할때 등록 수정 삭제 쿼리 일괄로 나감. (한번에 네트워크 태운다는 말이 아님. 설정으로 한번에 네트워크 태울 수도 있음.)

플러쉬 하는 방법

  • em.flush()
  • 트랜잭션 커밋 tx.commit()
  • JPQL 쿼리 실행

JPQL 쿼리 실행할 때 flush가 이루어져야 하는 이유

select * from member 하기 전에 member를 persist한 것들이 플러쉬가 안일어졌다면.. 못갖고오깄쥬

마이바티스타 JDBCTemplate 쓸 경우에는 수동으로 flush() 해줘야 해. 안그럼..ㅠㅠㅠ

플러시는 영속성 컨텍스트를 비우지 않음!!! 변경내용을 DB와 동기화 하는 작업

트랜잭션이라는 작업 단위가 중요. 커밋 직전에만 동기화 하면 됨!!! 그전에는 어떻게든 버퍼에서 유지하다가…

 

준영속 상태

영속에 있던 엔터티가 더이상 영속성 컨텍스트에서 분리(detached)

준영속 만드는 법

  • em.detach(entity);
  • em.clear(); 1차캐시 다 삭제. (플러시 안일어남.)
  • em.close();

스프링 쓸 때 준영속 많이 씀.

트랜잭션이 유지되는동안 이게 유지되는데.. 컨트롤러로 나가는 순간 영속성컨텍스트 유지가 안됨. 그럼 지연로딩 못쓰게 됨!!!

주의 !

얘가 LAZY잖아요. (Member에서 Team 관계매핑할때 Lazy)

LazyInitiallizationException

실전에서 개발하다보면 위에 오류 엄청 만날것임.

지연로딩 하려면 영속성컨텍스트에서 관리가 되어야 함.지연로딩 쓸거면 em을 닫으면 안됨. 그래서 음… 그러면 한 트랜잭션 내에서 레이지된거를 다 처리해줘야하는건가.

스프링에서는 트랜잭션 끝나고 컨트롤러에서 레이지로딩 하려고 할 때 저 에러 만날 것임. 영속성컨텍스트가 아니구나. 라고 이해를 하시면 됨. 준영속상태인 것을 레이지로딩 했구나 라고 생각하면 됨. 필요하면 준영속 들어가기 전에 미리 터치를 해놓거나(로딩을해놓거나) 하면 됩니다

이 기사는 저작권자의 CC BY 4.0 라이센스를 따릅니다.

JPA02. 관계

JPA04. Fetch

Comments powered by Disqus.