1월 1주차 스터디 발표 자료
개인 프로젝트를 진행하면서 도메인 설계 전에 Spring Data JPA에 대해 정리하고자 합니다!!😁
이미지 사용 출처 : https://youtu.be/OiAYmtq4Av8/
기초 개념
1. ORM(Object Relational Mapping)
객체가 테이블이 되도록 매핑시켜주는 프레임워크로, 프로그램의 복잡도를 줄이고 객체와 쿼리를 분리할 수 있다.
트랜잭션 처리나 기타 데이터베이스 관련 작업들을 좀 더 편리하게 처리할 수 있는 프레임워크이다.
ORM은 객체와 DB의 데이터를 자동으로 매핑해주기 때문에 직접 SQL문을 작성하지 않는다.
대표적 예시: JPA,Hibernate [Persistent API]
2. JPA(Java Persistent API)
JPA는 ORM과 관련된 인터페이스가 모아져있는 라이브러리, Java 진영의 표준 ORM이다.
한마디로 ORM은 큰 개념이고 JPA는 ORM을 구체화한 구현체이다.
- Hibernate
ORM 프레임워크 중 하나이다.
➔ JPA의 실제 구현체 중 하나이며, 현재 JPA 구현체 중 가장 많이 사용된다.- jpa의 구현체
- Spring Data JPA
Spring 프레임워크에서 JPA를 편리하게 사용할 수 있게 지원하는 라이브러리- CRUD 처리용 인터페이스 제공
- Repository 개발 시 인터페이스만 작성하면 구현 객체를 동적으로 생성해서 주입
- EntityManager를 자동으로 Bean으로 등록되기때문에, 직접 사용하지는 않는다.
➔ Hibernate에서 자주 사용되는 기능을 조금 더 쉽게 사용할 수 있게 구현해놓은 라이브러리
✔️ EntityManager?
데이터베이스에 엑세스하기 위해 사용되는 객체이며, EntityManager를 통해 데이터베이스에 데이터를 조회,등록,수정,삭제 작업을 수행한다.
➔ 기존 JPA를 사용하려면 EntityManager를 주입받아 사용해야하지만, SpringDataJPA는 JPA를 한단계 더 추상화 시킨 Repository 인터페이스를 제공한다. 해당 구현체는 스프링이 자동으로 생성해준다.
- jpaRepository는 Spring Data JPA에서 제공하는 JPA 구현을 위한 인터페이스로, 간단한 상속만으로 사전에 정의된 메서드를 활용하여 DB에 create/read/update/delete 쿼리를 수행한다.
2-1.jpaRepository
jpaRepository 인터페이스에 들어가보면, Spring Data JPA에서 사용하는 메서드가 정의되어있다.
- jpaRepository는 SimpleJpaRepository 클래스에서 구현되어있다.
- jpaRepository는 내부적으로 EntityManager가 대상 Entity의 데이터를 관리하고있기 때문에, 별도의 EntityManager의 구현이 필요없다.
3. Entity 생명주기
JPA를 이해하려면, Entity 생명주기를 이해하는 건 필수인 것 같아요.📖
Entity 생명주기에 관하여 정말 잘 정리되어있는 블로그를 발견하여 출처 남기고 정리해봅니다!
이미지 사용 출처 : https://siyoon210.tistory.com/138
3-1. 영속성 컨텍스트 (Persistence Context)
- 영속성 컨텍스트에서는 엔티티를 관리하며, EntityManager를 통해 DB의 데이터를 저장,조회,수정,삭제할 수 있다.
- 인스턴스로 존재하는 엔티티를 관리하고 영구 저장하는 논리적 영역이다.
- ⭐ 영속성 컨텍스트에서 관리하는 엔티티라고 해서 반드시 DB에 저장되는 것은 아니다.
✔️ 영속성?
데이터를 생성한 프로그램이 종료되어도 사라지지 않는 데이터의 특성. 즉, DB에 저장된 데이터이다.
3-2. 영속성 컨텍스트의 구조
- 1차 캐시 저장소
영속성 컨텍스트가 관리하는 엔티티 정보가 담겨있으며, 해당 저장소에 저장된 상태를영속상태
라고 한다.
영속 상태는 아직 DB에 저장되지 않은 상태이며, 단지 관리(managed)하는 상태이다. - 쿼리문 저장소
JPA는 필요한 쿼리문을 해당 저장소에 보관한다. 보관의 이유는 DB에 접근하는 횟수를 최소하여 성능향상을 이끌어낼 수 있다.
저장해둔 쿼리문으로 DB에 접근하는 행위는 EntityManager의 flush() 함수를 사용하면 된다.
3-3. Entity 생명주기
- 비영속상태(new,transient)
- 엔티티가 영속성 컨텍스트와 전혀 관련이 없는 상태
- 객체를 생성만 한 상태
1 2 3 4
// 객체를 생성한 상태 (비영속) Member member = new Member(); member.setId("Member1"); member.setUsername("회원1");
- 영속상태(managed)
- 엔티티가 영속성 컨텍스트에서 관리되고 있는 상태이다. 단, DB에 저장된 상태는 아니다.
- EntityManager의 persist()함수를 통해 엔티티를 영속상태로 만들 수 있다.
1
2
3
4
5
EntityManager entityManager = entityManagerFactory.createEntityManager();
entityManager.getTransaction().begin();
// 객체를 저장한 상태 (영속)
entityManager.persist(member);
➔ 엔티티를 저장하는 Insert 쿼리문이 생성되었으나, DB에 전달되지 않고 쿼리문 저장소에 보관된다.
➔ 즉, flush()가 실행되기 전에는 DB에 접근하지않는다. ➔ 엔티티를 저장하는 Insert 쿼리문이 생성되었으나, DB에 전달되지 않고 쿼리문 저장소에 보관된다.
➔ 즉, flush()가 실행되기 전에는 DB에 접근하지않는다. ➔ 여러개의 엔티티를 persist()하면, 해당하는 insert 쿼리문은 계속 쌓인다. ➔ 쌓인 쿼리문들은 flush()를 실행했을 때 DB에 반영된다. flush 이후에 entity는 사라지지않고 계속 관리된다.
➔ flush는 영속성 컨텍스트와 DB를 동기화하는 것 ➔ EntityManager가 DB에서 find()를 통해 조회한 데이터도 영속 상태인 엔티티가 된다.
➔ 조회한 데이터는 먼저 1차 캐시 저장소에 저장되고, 그 후 저장된 엔티티 정보를 반환한다.
⭐ 같은 엔티티를 한번 더 조회할 경우?
1차 캐시 저장소에 저장된 엔티티를 한번 더 조회할 경우에는 저장소에 있는 엔티티를 반환하고 실제 DB에는 접근하지 않는다! 동일한 엔티티이기 때문에, 인스턴스의 참조값도 동일하다.
3. 준영속상태(detached)
- 영속성 컨텍스트에서 관리하던 엔티티가 관리되지 않는 상태가되면 해당 엔티티를 준영속 상태라한다.
- 준영속 상태를 만드는 3가지 방법
- detach()사용
특정 엔티티를 준영속 상태로 만든다.1
entityManager.detach(member);
- clear()사용
영속성 컨텍스트 전체를 초기화한다. 저장해둔 쿼리문도 동시에 초기화가 된다.1
entityManager.clear();
- close()사용
영속성 컨텍스트를 닫는다. 관리되던 엔티티들은 모두 준영속 상태가된다.1
entityManager.close();
- remove()사용
삭제된 엔티티는 영속성 컨텍스트에서 관리하지 않게되며, 해당 엔티티를 DB에서 삭제하는 DELETE 쿼리문을 보관한다.
단, flush가 호출되기 전에는 실제 DB에 접근되지않는다.1
entityManager.remove(member);
- detach()사용
3-4. 변경감지
- update와 관련된 EntityManager의 메소드는 정의되어 있지않다. 단지, 변경을 감지할 뿐이다.
- 변경을 감지하는 원리?
1차 캐시저장소에는 본래 엔티티가 아닌, 엔티티에 대한 참조와 복사본인 SnapShot을 가지고있다.
flush()가 호출되고 실행하기 직전에, EntityManager는 복사복인 SnapShot과 실제 엔티티를 비교하여 값이 다르다면 변경을 감지한다.