플러시(flush()
)
- 영속성 컨텍스트의 변경 내용을 데이터베이스에 반영한다.
- 변경 감지를 통해 영속성 컨텍스트에 있는 엔티티들과 스냅샷을 비교하여 변경된 부분을 반영한다.
- 쓰기 지연 SQL 저장소의 쿼리를 데이터베이스에 날린다.
영속성 컨텍스트를 플러시 하는 방법
- em.flush(): 직접 호출
- 트랜잭션 커밋: 트랜잭션 커밋시에 플러시 실행
- JPQL 쿼리 실행: JPQL이나 Criteria 같은 객체지향 쿼리가 호출될 때 플러시 실행
JPQL 쿼리 실행 시 플러시가 자동으로 호출되는 이유
1
2
3
4
5
6
|
em.persist(memberA);
em.persist(memberB);
em.persist(memberC);
//중간에 JPQL 실행
query = em.createQuery("select m from Member m", Member.class);
List<Member> members= query.getResultList();
|
cs |
→ 기본적으로 persist로 의해 적재된 엔티티들은 쓰기 지연 SQL 저장소에 적재되어 있다가 커밋시에 데이터베이스에 반영된다 하지만 그 전에 JPQL로 조회하면 memberA, memberB, memberC에 대한 조회 결과를 받을 수 없으므로 이를 예방하기 위해 먼저 플러시를 실행하고 JPQL이 실행된다.
플러시 모드 옵션
em.setFlushMode(FlushModeType)
FlushModeType.AUTO
: 커밋이나 쿼리를 실행할 때 플러시 (기본값)FlushModeType.COMMIT
: 커밋할 때만 플러시
플러시 정리
- 영속성 컨텍스트를 비우지 않음
- 영속성 컨텍스트의 변경내용을 데이터베이스에 동기화
- 트랜잭션이라는 작업 단위가 있기에 가능함 → 커밋 직전에만 동기화
하면 됨
준영속 상태
- 영속 상태에서 준영속로 변환 가능
- 영속 상태의 엔티티가 영속성 컨텍스트에서 분리(detached)
- 영속성 컨텍스트가 제공하는 기능을 사용 못함
준영속 상태로 만드는 방법
em.detach(entity)
: 특정 엔티티만 준영속 상태로 전환em.clear()
: 영속성 컨텍스트를 완전히 초기화em.close()
: 영속성 컨텍스트를 종료
엔티티를 준영속 상태로 전환: detach()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
public void deteachedTest() {
EntityManagerFactory emf = Persistence.createEntityManagerFactory("hello");
EntityManager em = emf.createEntityManager();
EntityTransaction tx = em.getTransaction();
tx.begin();
// 회원 엔티티 생성, 비영속(new/transient) 상태
Member member = new Member();
member.setName("Kyeongho");
// 회원 엔티티 영속(managed) 상태
em.persist(member);
// 회원 엔티티를 영속성 컨텍스트에서 분리, 준영속(detached) 상태
em.detach(member);
tx.commit();
em.close();
}
|
cs |
→ em.detach(memeber)를 호출한 시점에서 1차 캐시부터 쓰기 지연 SQL 저장소까지 해당 엔티티를 관리하기 위한 모든 정보가 제거된다. 이렇게 영속 상태였다가 영속성 컨텍스트가 관리하지 않는 상태가된 상태를 준영속 상태라 한다.
영속성 컨텍스트 초기화: clear()
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
|
public void ClearTest() {
EntityManagerFactory emf = Persistence.createEntityManagerFactory("hello");
EntityManager em = emf.createEntityManager();
EntityTransaction tx = em.getTransaction();
tx.begin();
Member member1 = new Member();
member1.setName("Kyeongho");
// 새 엔티티 persist()이후 flush()를 통해 디비에 저장
em.persist(member1);
em.flush();
// 엔티티 조회, 영속 상태
Member member2 = em.find(Member.class, 1L);
em.clear(); // 영속성 컨텍스트 초기화
// 준영속 상태
member2.setName("ModifiedName");
tx.commit();
em.close();
}
|
cs |
→ member2에서 조회된 엔티티는 영속 상태이다. 그런 다음 clear()를 호출하게 되면 영속성 컨텍스트에 있는 모든 것이 초기화되기 때문에 member2도 준영속 상태가 된다.
병합: merge()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
public void mergeTest() {
EntityManagerFactory emf = Persistence.createEntityManagerFactory("hello");
EntityManager em = emf.createEntityManager();
EntityTransaction tx = em.getTransaction();
tx.begin();
// 비영속 상태
Member member1 = new Member();
member1.setName("Kyeongho");
// 영속 상태
em.persist(member1);
// 준영속 상태
em.detach(member1);
// 병합, 영속 상태
Member mergeMember = em.merge(member1);
System.out.println("em.contains(member1) = " + em.contains(member1));
System.out.println("em.contains(mergeMember) = " + em.contains(mergeMember));
tx.commit();
em.close();
}
|
cs |
실행결과
Hibernate:
/* insert me.kyeongho.Member
*/ insert
into
Member
(id, name)
values
(null, ?)
Hibernate:
/* load me.kyeongho.Member */ select
member0_.id as id1_0_0_,
member0_.name as name2_0_0_
from
Member member0_
where
member0_.id=?
em.contains(member1) = false
em.contains(mergeMember) = true
→ merge() 호출 시 준영속 상태의 엔티티를 통해 새롭게 병합된 영속 상태의 엔티티로 반환한다. 기존의 준영속 상태의 엔티티는 계속 준영속 엔티티로 남아있다.
비영속 병합
1
2
3
|
Member member = new Member();
Member newMember = em.merge(member);
tx.commit();
|
cs |
→병합(merge())는 비영속 엔티티도 영속 상태로 만들 수 있다. 즉 병합은 비영속, 준영속을 신경 쓰지 않는다.
'Study > spring' 카테고리의 다른 글
자바 ORM 표준 JPA 프로그래밍(6) - 엔티티 매핑 실습 (0) | 2020.12.27 |
---|---|
자바 ORM 표준 JPA 프로그래밍(5) - 엔티티 매핑 (0) | 2020.12.25 |
자바 ORM 표준 JPA 프로그래밍(3) - 영속성 컨텍스트 (0) | 2020.12.22 |
SpringBoot를 활용한 Hibernate 연동 JPA Basic 실습 (0) | 2020.12.21 |
자바 ORM 표준 JPA 프로그래밍(2) - JPA 시작 (0) | 2020.12.04 |