[카카오테크캠퍼스] JPA 엔티티 매핑, 영속성 컨텍스트
JDBC는 쿼리문을 써주고, Repository를 직접 써줘야했지만, JPA는 이를 훨씬 간편하게 구현할 수 있게 해준다.
SQL을 직접 다룰 때의 문제점
새로운 필드가 추가되면 관련된 SQL을 다 수정해야한다. 또한 개발자들이 엔티티를 신뢰하고 사용할 수 없다.
스키마 생성하는 방법
application.properties에
spring.jpa.hibernate.ddl-auto=create
이를 추가한다.
create: 기존 테이블 삭제 후 다시 생성 (DROP + CREATE)
create-drop: create와 같으나 종료시점에 테이블 DROP
update: 변경된 부분만 반영 (운영 DB에 사용하면 안됌)
validate: entity와 table이 정상 매핑되었는지만 확인
none: 사용하지 않음
@Entity
public class Menu {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(nullable = false)
private String name;
@Entity
엔티티 클래스임을 지정하며 테이블과 매핑된다.
@Table
엔티티가 매핑될 테이블을 지정하고 생략 시 엔티티 클래스 이름과 같은 테이블로 매핑된다.
@Id
id 필드임을 나타낸다.
@GeneratedValue
pk의 생성 규칙을 나타낸다. 위와 같이 하면 id Long일 때 자동으로 id값이 생성된다.
@Column
컬럼의 이름을 지정된 필드나 속성을 테이블의 컬럼에 매핑한다.
컬럼 이름을 지정하지 않으면 자동으로 필드의 이름으로 지정된다. 또한 nullable = false라고 선언하면 NOT NULL 속성이 추가된다
SpringData JPA
SpringData JPA를 쓰기 전에는 Repository에 관련 메서드를 직접 구현을 해야했다. 하지만 JPA를 쓰면 이러한 것들을 상속을 통해서 구현이 가능하다
JPARepository
JPA를 사용하여 데이터베이스를 조작하기 위한 메서드들을 제공한다.
public interface UserRepository extends JpaRepository<User, Long> {
@Query("SELECT u FROM User u WHERE u.age >= :age")
List<User> findByAgeGreaterThanEqual(@Param("age") Integer age);
}
이렇게 커스텀할수도 있고,
count, delete, deleteAll, deleteAllById, deleteById, existsById, findById, save 등의 기본적인 메서드를 제공해서 이걸 쓰면 된다!
findAll, findAllById, saveAll : List로 받는다.
영속성 컨텍스트
엔티티를 영구 저장하는 환경
persist() 메소드는 엔티티 매니저를 사용해서 회원 엔티티를 영속성 컨텍스트에 저장한다.
영속성 컨텍스트는 엔티티 매니저를 생성할 때 하나 만들어지고, 이를 통해서 영속성 컨텍스트에 접근할 수 있고, 이를 관리할 수 있다.
엔티티에는 4가지 상태가 존재한다.
비영속(New) : 엔티티 객체를 생성하고 아직 저장 안함
영속(Managed) : 엔티티 매니저를 통해서 엔티티를 영속성 컨텍스트에 저장
준영속(Detached) : 영속성 컨텍스트가 관리하던 영속 상태의 엔티티를 영속성 컨텍스트가 관리하지 않음
삭제(Removed) : 엔티티를 영속성 컨텍스트와 데이터베이스에서 삭제
생명주기는 이러하다
영속성 컨텍스트의 특징
영속성 컨텍스트는 엔티티를 식별자 값으로 구분한다. 따라서 영속상태는 식별자 값이 반드시 있어야한다.
JPA는 보통 트랜젝션을 커밋하는 순간 영속성 컨텍스트에 새로 저장된 엔티티를 데이터베이스에 반영하는데 이를 플러시(flush)라고 한다.
영속성 컨텍스트가 엔티티를 관리하면
-1차 캐시
-동일성 보장
-트랜젝션을 지원하는 쓰기 지연
-변경 감지
-지연 로딩
member 엔티티를 생성하고, em.persist(member)을 하면
이와 같은 상태가 된다.
em.find를 통해서 엔티티를 조회할 때에는
Member member = em.find(Member.class,"member1");
위와 같이 엔티티 클래스 타입과, 엔티티 식별자값을 파라미터로 넣으면 조회가 되고, 먼저 1차 캐시에 해당 값이 존재하는지 찾고, 만약 없으면 데이터베이스에서 조회한다.
만약 em.find()를 호출했는데 엔티티가 1차 캐시에 없으면 엔티티 매니저는 데이터베이스를 조회해서 엔티티를 생성한다. 그리고 이를 1차 캐시에 저장한 후 영속상태의 엔티티를 반환한다.
영속성 엔티티의 동일성 보장
Member a = em.find(Member.class, "member1");
Member b = em.find(Member.class, "member1");
여기서 a == b 하면 true가 반환된다.
동일성 : 실제 인스턴스가 같다.
동등성 : 실제 인스턴스는 다를 수 있지만 값이 같다.
엔티티 등록
EntityManager em = emf.createEntityManager();
EntityTransaction transaction = em.getTransaction();
//엔티티 매니저는 데이터 변경 시 트랜잭션을 시작해야 한다.
transaction.begin(); //[트랜잭션] 시작
em.persist(memberA);
em.persist(memberB);
//여기까지 INSERT SQL을 데이터베이스에 보내지 않는다.
//커밋하는 순간 데이터베이스에 INSERT SQL을 보낸다.
transaction.commit(); //[트랜잭션] 커밋
위와 같이 트랜젝션을 사용하면 엔티티 매니저는 트랜젝션을 커밋하기 직전까지 데이터베이스에 엔티티를 저장하지 않고 내부 쿼리 저장소에 INSERT SQL을 차곡차곡 모아둔다. 그리고 트랜젝션을 커밋할 떄 이 쿼리들을 데이터베이스에 보내는데 이것을 '트랜젝션을 지원하는 쓰기지연'이라고 한다.
우선 A를 영속화한다.
그 다음 B를 영속화한다.
이렇게 트랜젝션을 커밋하면 엔티티매니저는 영속성 컨텍스트를 flash한다.
이렇게 영속성 컨텍스트의 변경 내용을 데이터베이스에 동기화하고, 실제 데이터베이스에 트랜잭션을 커밋한다.
참조
[JPA] JPARepository에 대해 알아보자(+사용법, Method)
안녕하세요. 쭈피셜입니다!9기 여러분 모두 개발은 잘하고 계신가요?Spring 수업도 끝이 나고 이제 대망의 프론트수업만 남아 있습니다.점점 종강이 가까워지고 있습니다. 종강이 가까워진다는
velog.io
https://m.yes24.com/Goods/Detail/19040233
자바 ORM 표준 JPA 프로그래밍 - 예스24
자바 ORM 표준 JPA는 SQL 작성 없이 객체를 데이터베이스에 직접 저장할 수 있게 도와주고, 객체와 관계형 데이터베이스의 차이도 중간에서 해결해준다. 이 책은 JPA 기초 이론과 핵심 원리, 그리고
m.yes24.com