Java EE는 자바 엔터프라이즈 에디션으로 EJB, JSP, Servlet, JNDI 같은 기능을 지원하며 자바를 이용한 서버측 개발을 위한 플랫폼
엔티티의 생명주기
비영속 (new/transient) : 영속성 컨텍스트와 전혀 관계가 없는 새로운 상태
영속 (managed) : 영속성 컨텍스트에 관리되는 상태
준영속 (detached) : 영속성 컨텍스트에 저장되었다가 분리된 상태
삭제 (removed) : 삭제된 상태
- 비영속
//객체를 생성한 상태(비영속)
Member member = new Member();
member.setId("member1");
member.setUsername("회원1");
- 영속
//객체를 생성한 상태(비영속)
Member member = new Member();
member.setId("member1");
member.setUsername("회원1");
EntityManager em = emf.createEntityManager();
em.getTransaction().begin();

//객체를 저장한 상태(영속)
em.persist(member);
- 준영속
//회원 엔티티를 영속성 컨텍스트에서 분리, 준영속 상태
em.detach(member);
준영속 상태란?
영속 -> 준영속
영속 상태의 엔티티가 영속성 컨텍스트에서 분리(detached)
영속성 컨텍스트가 제공하는 기능을 사용 못함(업데이트같은 거)
[준영속 상태로 만드는 방법]
em.detach(entity) : 특정 엔티티만 준영속 상태로 전환
em.clear() : 영속성 컨텍스트를 완전히 초기화
em.close() : 영속성 컨텍스트를 종료
- 삭제
//객체를 삭제한 상태(삭제)
em.remove(member);
영속성 컨텍스트의 이점
1차 캐시
동일성(identity) 보장
트랜잭션을 지원하는 쓰기 지연(transactional write-behind)
변경 감지(Dirty Checking)
지연 로딩(Lazy Loading)
엔티티 조회, 1차 캐시
//객체를 생성한 상태(비영속)
Member member = new Member();
member.setId("member1");
member.setUsername("회원1");
//엔티티를 영속
em.persist(member);
1차 캐시에서 조회
//객체를 생성한 상태(비영속)
Member member = new Member();
member.setId("member1");
member.setUsername("회원1");
//객체를 저장한 상태(영속) -> 1차 캐시에 저장됨
em.persist(member);
//1차 캐시에서 조회
Member findMember = em.find(Member.class, "member1");
데이터베이스에서 조회
Member findMember2 = em.find(Member.class, "member2");
영속 엔티티의 동일성 보장
Member a = em.find(Member.class, "member1");
Member b = em.find(Member.class, "member1");
System.out.println(a == b); //동일성 비교 true
1차 캐시로 반복 가능한 읽기(REPEATABLE READ) 등급의 트랜잭션 격리 수준을 데이터베이스가 아닌 애플리케이션 차원에서 제공
엔티티 등록 - 트랜잭션을 지원하는 쓰기 지연
EntityManager em = emf.createEntityManager();
EntityTransaction transaction = em.getTransaction();
//엔티티 매니저는 데이터 변경시 트랜잭션을 시작해야 한다.
transaction.begin(); // [트랜잭션] 시작
em.persist(memberA);
em.persist(memberB);
//여기까지 INSERT SQL을 데이터베이스에 보내지 않는다.
//커밋하는 순간 데이터베이스에 INSERT SQL을 보낸다.
transaction.commit(); // [트랜잭션] 커밋
[em.persist(memberA);]
[em.persiste(memberB);]
[transaction.commit();]
엔티티 수정 - 변경 감지
EntityManager em = emf.createEntityManager();
EntityTransaction transaction = em.getTransaction();
transaction.begin(); // [트랜잭션] 시작
// 영속 엔티티 조회
Member memberA = em.find(Member.class, "memberA");
// 영속 엔티티 데이터 수정
memberA.setUsername("hi");
memberA.setAge(10);
//em.update(member) 이런 코드가 있어야 하지 않을까?
transaction.commit(); // [트랜잭션] 커밋
변경 감지
엔티티 삭제
//삭제 대상 엔티티 조회
Member memberA = em.find(Member.class, “memberA");
em.remove(memberA); //엔티티 삭제
플러시
연속성 컨테스트의 변경내용을 데이터베이스에 반영(1차 캐시에 영향을 주지 않음.)
영속성 컨텍스트를 비우지 않음
영속성 컨텍스트의 변경내용을 데이터베이스에 동기화
트랜잭션이라는 작업 단위가 중요 -> 커밋 직전에만 동기화하면 됨
플러시 발생
변경 감지
수정된 엔티티 쓰기 지연 SQL 저장소에 등록
쓰기 지연 SQL 저장소의 쿼리를 데이터베이스에 전송(등록, 수정, 삭제 쿼리)
영속성 컨텍스트를 플러시하는 방법
em.flush() (직접 호출)
트랜잭션 커밋 (플러시 자동 호출)
JPQL 쿼리 실행 (플러시 자동 호출)
[JPQL 쿼리 실행시 플러시가 자동으로 호출되는 이유]
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();
[플러시 모드 옵션]
em.setFlushMode(FlushModeType.COMMIT)
- FlushModeType.AUTO : 커밋이나 쿼리를 실행할 때 플러시(기본값)
- FlushModeType.COMMIT : 커밋할 때만 플러시
Commit
트랜잭션을begin()으로 수행한 뒤commit()하여 트랜잭션을 종료해야함.
커밋을 수행하게 되면 내부적으로EntityManager의flush()메서드를 호출한 후 트랜잭션을 닫음.
참고 : Commit vs Flush flush는 쿼리를 전송하는 역할이고 commit은 내부적으로 flush를 수행한 뒤 트랜잭션을 끝내는 역할 즉 flush로 전송된 쿼리는 rollback할 수 있지만 commit은 트랜잭션을 끝내므로 rollback 할 수 없음.