LUMI_dev
Entity- #5. Entity의 상태 본문
1. 비영속 (Transient)
2. 영속 (Managed)
3. 준영속 (Detached)
4. 삭제 (Removed)
1. 비영속 (Transient)
- new 연산자를 통해 인스턴스화된 Entity 객체
- 아직 영속성 컨텍스트에 저장 안됨 → JPA의 관리 받지 않음
- JPA가 관리하지 못하기 때문에 해당 객체의 데이터를 변경해도 변경 감지 이뤄지지 않음
Memo memo = new Memo(); // 비영속 상태
memo.setId(1L);
memo.setUsername("Robbie");
memo.setContents("비영속과 영속 상태");
2. 영속 (Managed)
.persist(entity) : EntityManager를 통해 비영속 Entity를 영속성 컨텍스트에 저장 / 관리되고 있는 상태됨
em.persist(memo);
3. 준영속 (Detached)
영속성 컨텍스트에 저장되어 관리되다가 분리된 상태
영속 상태에서 준영속 상태로 바꾸는 3가지 방법
detach(entity) | 특정 Entity만 준영속 상태로 전환 Managed가 Detached로 전환 |
clear() | 영속성 컨텍스트 완전히 초기화 |
close() | 영속성 컨텍스트 종료 |
방법 1. detach(entity)
em.detach(memo);
코드
@Test
@DisplayName("준영속 상태 : detach()")
void test2() {
EntityTransaction et = em.getTransaction();
et.begin();
try {
Memo memo = em.find(Memo.class, 1);
System.out.println("memo.getId() = " + memo.getId());
System.out.println("memo.getUsername() = " + memo.getUsername());
System.out.println("memo.getContents() = " + memo.getContents());
// em.contains(entity) : Entity 객체가 현재 영속성 컨텍스트에 저장되어 관리되는 상태인지 확인하는 메서드
System.out.println("em.contains(memo) = " + em.contains(memo));
System.out.println("detach() 호출");
em.detach(memo);
System.out.println("em.contains(memo) = " + em.contains(memo));
System.out.println("memo Entity 객체 수정 시도");
memo.setUsername("Update");
memo.setContents("memo Entity Update");
System.out.println("트랜잭션 commit 전");
et.commit();
System.out.println("트랜잭션 commit 후");
} catch (Exception ex) {
ex.printStackTrace();
et.rollback();
} finally {
em.close();
}
emf.close();
}
em.find(Memo.class,1); 메서드 호출 후 Managed 상태
em.detach(memo); 메서드를 호출하여
특정 Entity 객체 Memo #1을 영속성 컨텍스트에서 제거
→ 준영속 상태로 전환
memoEntity 객체의 데이터를 수정해도 변경 감지 x
→ Update SQL 수행되지 않음
em.contains(memo);
객체가 영속성 컨텍스트에 저장되어 관리되는 상태인지
확인하는 메서드
방법 2. clear();
영속성 컨텍트 초기화
em.clear();
- 영속성 컨텍스트의 모든 Entity를 준영속 상태로 전환
- 영속성 컨텍스트 틀은 유지하지만 내용은 비워 새로 만든 것과 같은 상태
- 영속성 컨텍스트 계속 이용할 순 있음
코드
@Test
@DisplayName("준영속 상태 : clear()")
void test3() {
EntityTransaction et = em.getTransaction();
et.begin();
try {
//memo#1 Entity를 조회
Memo memo1 = em.find(Memo.class, 1);
Memo memo2 = em.find(Memo.class, 2);
// em.contains(entity) : Entity 객체가 현재 영속성 컨텍스트에 저장되어 관리되는 상태인지 확인하는 메서드
System.out.println("em.contains(memo1) = " + em.contains(memo1));
System.out.println("em.contains(memo2) = " + em.contains(memo2));
//clear()시키기 - .contains() = false
System.out.println("clear() 호출");
em.clear();
System.out.println("em.contains(memo1) = " + em.contains(memo1));
System.out.println("em.contains(memo2) = " + em.contains(memo2));
//memo#1 Entity를 다시 조회 - .contains() = true
System.out.println("memo#1 Entity 다시 조회");
Memo memo = em.find(Memo.class, 1);
System.out.println("em.contains(memo) = " + em.contains(memo));
System.out.println("\n memo Entity 수정 시도");
memo.setUsername("Update");
memo.setContents("memo Entity Update");
System.out.println("트랜잭션 commit 전");
et.commit();
System.out.println("트랜잭션 commit 후");
} catch (Exception ex) {
ex.printStackTrace();
et.rollback();
} finally {
em.close();
}
emf.close();
}
em.clear(); 메서드 호출 후 완전히 비워진 영속성 컨텍스트
em.clear(); 메서드 호출 후 em.contains(); 메서드 확인했을 때 false
방법 3. close();
영속성 컨텍스트를 종료
em.close();
- 영속성 컨텍스트가 관리하던 영속성 상태의 모든 Entity들 모두 준영속 상태로 변경
- 영속성 컨텍스트 더이상 사용할 수 없음
@Test
@DisplayName("준영속 상태 : close()")
void test4() {
EntityTransaction et = em.getTransaction();
et.begin();
try {
Memo memo1 = em.find(Memo.class, 1);
Memo memo2 = em.find(Memo.class, 2);
// em.contains(entity) : Entity 객체가 현재 영속성 컨텍스트에 저장되어 관리되는 상태인지 확인하는 메서드
System.out.println("em.contains(memo1) = " + em.contains(memo1));
System.out.println("em.contains(memo2) = " + em.contains(memo2));
System.out.println("close() 호출");
em.close();
Memo memo = em.find(Memo.class, 2); // Session/EntityManager is closed 메시지와 함께 오류 발생
System.out.println("memo.getId() = " + memo.getId());
} catch (Exception ex) {
ex.printStackTrace();
et.rollback();
} finally {
em.close();
}
emf.close();
}
em.close(); 메서드 호출 후 EntityManger 사용하려고 하면 오류 발생
준영속 상태에서 다시 영속 상태로 바꾸는 방법
merge(entity)
em.merge(memo);
- 전달 받은 Entity를 사용하여 새로운 영속 상태의 Entity 반환
- 비영속, 준영속 모두 파라메터로 받을 수 있음
- 상황에 따라 '저장' or '수정' 함
- 동작 방법
- 파라메터로 전달된 Entity 식별자 값으로 영속성 컨텍스트 조회
- 해당 Entity가 영속성 컨텍스트에 없다면?
- DB에서 새롭게 조회
- 조회한 Entity, 영속성 컨텍스트에 저장
- 전달 받은 Entity 값을 사용하여 merge(병합)
- Update SQL이 수행 (수정)
- 만약 DB에도 없다면?
- 새롭게 생성한 Entity를 영속성 컨텍스트에 저장
- Insert SQL 수행 (저장)
- 해당 Entity가 영속성 컨텍스트에 없다면?
- 파라메터로 전달된 Entity 식별자 값으로 영속성 컨텍스트 조회
예시)
A. merge(entity) 저장
@Test
@DisplayName("merge() : 저장")
void test5() {
EntityTransaction et = em.getTransaction();
et.begin();
try {
Memo memo = new Memo();
memo.setId(3L);
memo.setUsername("merge()");
memo.setContents("merge() 저장");
System.out.println("merge() 호출");
Memo mergedMemo = em.merge(memo);
System.out.println("em.contains(memo) = " + em.contains(memo));
System.out.println("em.contains(mergedMemo) = " + em.contains(mergedMemo));
System.out.println("트랜잭션 commit 전");
et.commit();
System.out.println("트랜잭션 commit 후");
} catch (Exception ex) {
ex.printStackTrace();
et.rollback();
} finally {
em.close();
}
emf.close();
}
em.merge(memo) 호출 후 영속성 컨텍스트에 Memo#3 객체 저장 + Insert SQL
em.merge(memo); 호출 후 영속성 컨텍스트 및 DB 모두
해당 값이 없기 때문에 새롭게 생성 > 영속성 컨텍스트 저장 > Insert SQL 수행
비영속의 memo = false
merged된 memo = true
B. merge(entity) 수정
@Test
@DisplayName("merge() : 수정")
void test6() {
EntityTransaction et = em.getTransaction();
et.begin();
try {
Memo memo = em.find(Memo.class, 3);
System.out.println("memo.getId() = " + memo.getId());
System.out.println("memo.getUsername() = " + memo.getUsername());
System.out.println("memo.getContents() = " + memo.getContents());
System.out.println("em.contains(memo) = " + em.contains(memo));
System.out.println("detach() 호출");
em.detach(memo); // 준영속 상태로 전환
System.out.println("em.contains(memo) = " + em.contains(memo));
System.out.println("준영속 memo 값 수정");
memo.setContents("merge() 수정");
System.out.println("\n merge() 호출");
Memo mergedMemo = em.merge(memo);
System.out.println("mergedMemo.getContents() = " + mergedMemo.getContents());
System.out.println("em.contains(memo) = " + em.contains(memo));
System.out.println("em.contains(mergedMemo) = " + em.contains(mergedMemo));
System.out.println("트랜잭션 commit 전");
et.commit();
System.out.println("트랜잭션 commit 후");
} catch (Exception ex) {
ex.printStackTrace();
et.rollback();
} finally {
em.close();
}
emf.close();
}
영속성 컨텍스트에는 없으나 DB에 존재할 경우
1. DB에서 식별자 값을 사용하여 조회한 후
2. 영속성 컨텍스트에 저장 > 객체에 병합 및 반환
3. 트랜잭션 commit 후 Update SQL 수행
4. 삭제 (Removed)
삭제하기 위해 조회해온 영속 상태의 Entity를 파라메터로 전달 받아 삭제 상태로 전환
em.remove(memo);