JPA란?
- Java Persistence API
- 자바 진영의 ORM 기술 표준
- JPA는 애플리케이션과 JDBC 사이에서 동작한다.
- 표준 명세이다
- 인터페이스의 모음
- JPA 표준 명세를 구현한 3가지 구현체
- 하이버네이트, EclipseLink, DataNucleus
ORM이란?
- Object relational mapping - 객체 관계 매핑
- 객체는 객체대로 설계
- 관계형 데이터베이스는 관계형 데이터베이스대로 설계
- ORM 프레임워크가 중간에서 매핑
- 대중적인 언어에는 대부분 ORM 기술이 존재한다.
JPA를 사용하는 이유
- SQL 중심적인 개발에서 객체 중심으로 개발 : https://my-dev-record.tistory.com/12
- 생산성 : 객체 중심으로 개발하게 되므로 매핑에 투자해야할 시간이 줄어든다.
- 유지보수 : 객체에 필드가 추가되어도 SQL을 수정하지 않아도 된다.
- 패러다임의 불일치 해결 (위에 링크한 곳에 설명한 문제들을 해결해준다.)
- JPA와 상속
- JPA와 연관관계
- JPA와 객체 그래프 탐색
- JPA와 비교하기
- 패러다임의 불일치를 해결하여 신뢰할 수 있는 엔티티와 계층을 갖는다.
- 데이터 접근 추상화와 벤더 독립성
- 표준
JPA 영속성 컨텍스트 설명 및 성능
- JPA를 이해하는데 가장 중요한 언어
- 엔티티를 영구 저장하는 환경이라는 뜻
- Entitymanager.persist(entity);
- persist는 DB에 저장하는 기능을 하지만, 영속성 컨텍스트를 통해서 이 엔티티라는걸 영속화하는 것이다.
- 혹은 엔티티를 영속성 컨텍스트에 저장하는 것이다.
- 영속성 컨텍스트는 논리적 개념
- 눈에 보이지 않는다
- 엔티티 매니저를 통해서 영속성 컨텍스트에 접근
1차 캐시와 동일성 보장 내용
동일한 트랜잭션에서만 보장된다.
영속성 컨텍스트에서 1차 캐시의 영역이 존재한다.
1차 캐시는 @Entity로 등록한 클래스의 @Id 필드를 키로 설정한다.
또한 @Entity 클래스의 인스턴스가 저장된다.
아래 코드 내용을 설명하면,
- 영속성 컨텍스트 1차 캐시 영역에 아무런 데이터가 없다.
- member1
- 1차 캐시 내에 내용이 없으므로 DB에서 데이터를 조회한다.
- 조회한 데이터의 PK(@Entity의 @Id)의 값을 키로, 데이터 전체(@Entity)를 1차 캐시에 저장한다.
- member2
- 1차 캐시에 데이터가 있으므로 1차 캐시 먼저 확인한다.
- 1차 캐시에 키가 100인 데이터가 존재하는지 확인한다.
- 데이터가 존재하므로 DB에 SQL를 실행해 확인하는 것이 아닌, 1차 캐시에서 데이터를 읽어온다.
String id = "100";
Member member1 = jpa.find(Member.class, id); // SQL 동작
Member member2 = jpa.find(Member.class, id); // 캐시
member1 == member2 // true
트랜잭션을 지원하는 쓰기 지연(버퍼의 개념)
영속성 컨텍스트에 쓰기 지연 SQL 저장소가 존재한다.
데이터의 변경(Insert, Update, Delete)의 경우 SQL만 작성하여 놓고 쓰기 지연 SQL 저장소에 SQL을 모아둔다.
트랜잭션을 커밋할 때 모아둔 SQL을 실행한다.
em.persist의 경우 영속화하여 영속성 컨텍스트에서 관리하는 상태로 변경하는 것이다.
transaction.begin(); // 트랜잭션 시작
em.persist(memberA);
em.persist(memberB);
em.persist(memberC);
// 여기까지 INSERT SQL을 데이터베이스에 보내지 않는다.
// 커밋하는 순간 데이테베이스에 INSERT SQL을 모아서 보낸다.
transaction.commit();
지연 로딩과 즉시 로딩
지연 로딩 : 객체가 실제 사용될 때 로딩
즉시 로딩 : JOIN SQL로 한번에 연관된 객체까지 미리 조회
// * 지연 로딩
Member member = memberDAO.find(memberId); // SELECT * FROM MEMBER
Team team = Member.getTeam();
String teamName = team.getName(); // SELECT * FROM TEAM
// * 즉시로딩
Member member = memberDAO.find(memberId); // SELECT A.*, B.* FROM MEMBER JOIN TEAM ...
Team team = member.getTeam();
String teamName = team.getName();
변경 감지
영속성 컨텍스트의 1차 캐시에 스냅샷이 존재한다.
스냅샷은 1차 캐시에 Entity가 등록될 때 같이 저장되고, 트랜잭션의 commit을 실행할 때 Entity와 스냅샷을 비교하여 변경을 감지한다.
데이터의 변경이 발생했다면 UPDATE SQL을 작성하여 쓰기 지연 SQL 저장소에 저장하고 저장되어 있던 SQL과 함께 DB에 전달되어 실행된다.
Member member = em.find(Member.class, 100L);
System.out.println("member.id : " + member.getId()); // 100
System.out.println("member.name : " + member.getName()); // A
member.setName("B");
tx.commit();
엔티티의 생명주기
비영속(new/transient) : 영속성 컨텍스트와 전혀 관계가 없는 새로운 상태
Member member = new Member();
member.setId(100L);
member.setName("helloJPA");
영속(managed) : 영속성 컨텍스트에 관리되는 상태
em.persist(member);
준영속(detached) : 영속성 컨텍스트에 저장되었다가 분리된 상태
em.detach(member);
삭제(removed) : 삭제된 상태
em.remove(member);
Reference
자바 ORM 표준 JPA 프로그래밍(인프런, 김영한)
'framework > jpa' 카테고리의 다른 글
[JPA] 엔티티 매핑 3 (0) | 2023.04.23 |
---|---|
[JPA] 엔티티 매핑 2 (0) | 2023.04.09 |
[JPA] 엔티티 매핑 1 (0) | 2023.04.08 |
[JPA] 기본 사용 방법 (0) | 2023.04.07 |
[JPA] JPA 사용 전 객체지향 프로그래밍의 불편함 (0) | 2023.04.07 |