jpa 란?
JPA 저장
멤버객체를 만든다고 가정해보자
멤버 객체를 회원 DAO 에 넘기고 회원 DAO 가 JPA 에게 멤버 회원 객체를 저장해줘 라고 던지기만 하면 JPA 가 자동으로 JPA 가 회원 객체를 분석하고 자동으로 INSERT SQL 을 만들어줘도 JDBC API 를 사용해서 db 에 insert 쿼리를 날려준다.
또한 패러다임의 불일치도 해결해준다.
자바 컬렉션의 저장하듯 한줄의 코드로 JPA 에게 회원을 저장시킬 수 있따.
이떄 회원가 같은 객체를 JPA 에서 엔티티라 부른다.
엔티티란? DB 테이블에 대응하는 하나의 클래스라 생각하면 된다.
JPA 조회
조회또한 마찬가지로 JPA 가 다 알아서 해준다. EnityObject 를 잘 만들어서 결과로 돌려준다.
jpa 에서 가장 중요한 두가지가 있다.
- 객체와 관계형 데이터 베이스 매핑하기(Object Relational Mapping)
- 영속성 컨텍스트
영속성은 JPA 를 이해하는 가장 중요한 용어이다.
"엔티티를 영구 저장하는 환경" 이라는 뜻이다.
엔티티 매니저?
영속성 컨텍스트는 논리적인 개념으로 눈에 보이지 않는다.
엔티티 매니저를 통해서 영속성 컨텍스트에 접근한다.
EntityManager.persist(entity);
// 객체를 생성한 상태(비영속)
Member member = new Member();
member.setId("member1");
member.setUsername("회원1");
// 객체를 생성한 상태(비영속)
Member member = new Member();
member.setId("member1");
member.setUsername("회원1");
EntityManagerFactory emf = Persistence.createEntityManagerFactory("hello");
EntityManager em = emf.createEntityManager();
EntityTransaction tx = em.getTransaction();
// 엔티티 매니저는 데이터 변경 시 트랜잭션을 시작해야한다.
tx.begin();
// 객체를 생성한 상태(비영속)
Member member = new Member();
member.setId("member1");
member.setUsername("회원1");
// 객체를 저장한 상태(영속)
em.persist(member);
1차 캐시 조회
find 문 조회시 1차 캐시에서 우선 조회 후 있을 경우 해당 캐시의 엔티티를 반환하고 없을 경우 DB 에서 조회하여 1차캐시에 저장 후 캐시의 엔티티 값을 반환한다.
Member member = new Member();
member.setId("member1");
member.setName("회원1");
//1차 캐시에 저장됨
em.persist(member);
//1차 캐시에서 조회
Member findMember = em.find(Member.class, "member1");
// db 에서 조회 : select 문 날라감
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) 등급의 트랜잭션 격리 수준을 데이터베이스가 아닌 애플리케이션 차원에서 제공
엔티티 등록
트랜잭션을 지원하는 쓰기 지연
- JPA 는 persist 문장 실행시 바로 db 에 insert 문을 실행하는 것이 아닌 트랜잭션은 커밋하는 순간에 db 에 insert 문을 실행한다.
EntityManager em = emf.createEntityManager();
EntityTransaction transaction = em.getTransaction();
//엔티티 매니저는 데이터 변경시 트랜잭션을 시작해야 한다.
transaction.begin(); // [트랜잭션] 시작
em.persist(memberA);
em.persist(memberB);
//여기까지 INSERT SQL을 데이터베이스에 보내지 않는다.
//커밋하는 순간 데이터베이스에 INSERT SQL을 보낸다.
transaction.commit(); // [트랜잭션] 커밋
- persist 시 쓰기 지연 SQl 저장소에 insert 문을 보관하였다가 transaction.commit() 시 jpa 에서 flush 가 동작하면서 실제로 insert 문이 실행된 후 실제 db commit 이 실행됩니다.
엔티티 수정
변경감지
- 커밋을 하면 내부적으로 flush 가 호출된다. 그 이후 엔티티와 스냅샷을 비교한다.
- 1차 캐시 내부에는 pk 인 id , 와 엔티티, 스냅샷이 존재한다.
- 스냅샷은 db 에서 읽어온 값이든 내가 집어넣은 값이든 최초의 상태를 스냅샷으로 찍어둔다.
- 즉 최초로 영속성 컨텍스트에 들어온 상태를 스냅샷으로 찍어둔다.
커밋 순간 플러시가 되면서 jpa 는 엔티티와 스냅샷을 일일히 다 비교후 값이 다른 부분을 update 쿼리로 생성하여 쓰기 지연 sql 에 저장해둔다.
그리고 쓰기 지연 저장소에서 최종적으로 업데이트가 된다.
플러시란?
영속성 컨텍스트의 변경 내용을 데이터베이스에 반영하는 것을 말한다.
즉 영속성 컨텍스트의 있는 쿼리들을 db 에 실행하는 것이다.
데이터베이스 트랜잭션이 커밋되면 플러시가 자동으로 발생한다.
플러시 발생시
- 변경감지
- 수정된 엔티티 쓰기 지연 SQL 저장소에 등록
- 쓰기 지연 SQL 저장소의 쿼리를 데이터 베이스에 전송 (등록, 수정 , 삭제 쿼리)
영속성 컨텍스트 플러시하는 방법
em.flush() - 직접 호출 // 거의 쓸일이 없지만 테스트 시 필요
트랜잭션 커밋 - 플러시 자동 호출
JPQL 쿼리 실행 - 플러시 자동 호출
'JPA' 카테고리의 다른 글
공통 인터페이스 기능 (1) | 2024.12.07 |
---|---|
양방향 연관관계와 연관관계 주인 (0) | 2024.12.05 |