엔티티 생명주기
비영속 (new/transient)
- 영속성 컨텍스트와 전혀 관계가 없는 새로운 상태
영속 (managed)
- 영속성 컨텍스트에 관리되는 상태
준영속 (detached)
- 영속성 컨텍스트에 저장되었다가 분리된 상태
삭제 (removed)
- 삭제된 상태
영속성 컨텍스트는 엔티티를 관리하는 환경으로 Key와 그에 해당하는 객체로 엔티티를 관리한다.
영속성 컨텍스트를 동해 얻는 이점
- 1차 캐시에 저장하여 관리함으로 실제 DB에 커넥팅 하지 않고 DB의 값을 조회하는 등 성능상 이점
- 캐시를 통해 관리함으로 트렌젝션 내 동일성(identity) 보장
- 트랜잭션을 지원하는 쓰기 지연 (transactional write-behind)
- 변경 감지(Dirty Checking)를 통한 저장
- 지연 로딩(Lazy Loading)
Member 엔티티
@Entity
@Getter
@Setter
public class Member {
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE)
private Long id;
private String name;
@Enumerated(EnumType.STRING)
private RoleType roleType;
@ManyToOne
@JoinColumn(name = "TEAM_ID")
private Team team;
}
Team 엔티티
@Entity
@Getter
@Setter
public class Team {
@Id
@GeneratedValue
private Long id;
private String teamName;
@OneToMany(mappedBy = "team")
private List<Member> members = new ArrayList<>();
}
영속성 컨텍스트의 처리 테스트
@SpringBootApplication
public class Ex1HelloJpaApplication {
public static void main(String[] args) {
SpringApplication.run(Ex1HelloJpaApplication.class, args);
EntityManagerFactory emf = Persistence.createEntityManagerFactory("hello");
EntityManager em = emf.createEntityManager();
EntityTransaction tx = em.getTransaction();
tx.begin();
try {
Team team = new Team();
team.setTeamName("teamHello");
Member member = new Member();
member.setName("HelloA");
member.setRoleType(RoleType.ADMIN);
member.setTeam(team);
//지연 쓰기확인을 위한 출력
System.out.println("before");
em.persist(team);
em.persist(member);
System.out.println("after");
Member find = em.find(Member.class, 1);
System.out.println(find.getName());
tx.commit();
} catch (Exception e) {
tx.rollback();
} finally {
em.close();
emf.close();
}
}
}
1. Team객체와 Member객체를 생성한다.
2. 지연 쓰기 기능을 확인하기 위한 저장 전 후에 "before" , "after" 출력 테스트
3. 영속성 컨텍스트 내에 엔티티를 관리함을 확인하기 위한 조회
- 실제 쿼리를 날리지 않고 관리되고 있는 컨텍스트 내에서 객체를 가져옴
4. 이상이 없으면 커밋, 예외 발생 시 롤백, EntityManager 와 EntityManagerFactory의 커넥션 반환
실제 쿼리문
변경 감지 테스트
@SpringBootApplication
public class Ex1HelloJpaApplication {
public static void main(String[] args) {
SpringApplication.run(Ex1HelloJpaApplication.class, args);
EntityManagerFactory emf = Persistence.createEntityManagerFactory("hello");
EntityManager em = emf.createEntityManager();
EntityTransaction tx = em.getTransaction();
tx.begin();
try {
Member find = em.find(Member.class, 1);
find.setName("newName");
tx.commit();
} catch (Exception e) {
tx.rollback();
} finally {
em.close();
emf.close();
}
}
}
저장한 DB를 조회하여 내부 프로퍼티의 값을 변경하였다.
JPA의 더티 채킹 기능으로 persist하지 않았음에도 변경을 감지하여 업데이트 쿼리를 날린 것을 확인할 수 있다.
쿼리 로그
Member의 이름만 변경하기 위해 조회해 왔는데
자동으로 연관관계에 있는 Member를 ID로 조인해 오는 것을 확인할 수 있다.
지연 로딩
Member 엔티티의 연관관계 매핑되어 있는 Team의 조회를 지연로딩으로 변경(default = 즉시로딩)
@Entity
@Getter
@Setter
public class Member {
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE)
private Long id;
private String name;
@Enumerated(EnumType.STRING)
private RoleType roleType;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "TEAM_ID")
private Team team;
}
MemberDB 조회
@SpringBootApplication
public class Ex1HelloJpaApplication {
public static void main(String[] args) {
SpringApplication.run(Ex1HelloJpaApplication.class, args);
EntityManagerFactory emf = Persistence.createEntityManagerFactory("hello");
EntityManager em = emf.createEntityManager();
EntityTransaction tx = em.getTransaction();
tx.begin();
try {
Member find = em.find(Member.class, 1);
find.setName("newName2");
tx.commit();
} catch (Exception e) {
tx.rollback();
} finally {
em.close();
emf.close();
}
}
}
쿼리 로그
지연로딩으로 설정함으로 Team이 필요하지 않다면 조회해 올 당시에 Join 하지 않고 Member의 엔티티만 조회해 온다.
코드 출처 및 참고 자료
인프런 / 김영한 / 자바 ORM 표준 JPA 프로그래밍 - 기본편
https://www.inflearn.com/course/ORM-JPA-Basic/dashboard
'JPA' 카테고리의 다른 글
Querydsl 정리 (0) | 2024.03.29 |
---|---|
JPA , QueryDsl 수정 중 에러 해결 (0) | 2024.03.17 |
JPQL문법 2 (페치 조인,벌크 연산) (0) | 2022.12.23 |
JPQL 문법 1 (1) | 2022.12.22 |
JPA 쿼리 언어 종류 (1) | 2022.12.22 |