DB 테이블에 대응하는 하나의 클래스. JPA가 관리한다.
기본 생성자가 필수(파라미터가 없는 public 또는 protected)
엔티티와 매핑 할 테이블 지정
데이터베이스 PK와 매핑
PK를 자동으로 생성해주는 애노테이션
(strategy = GenerationType.IDENTITY) - 데이터베이스에 위임
(strategy = GenerationType.SEQUENCE) - 데이터베이스 시퀀스 오브젝트 사용
(strategy = GenerationType.TABLE) - 키 생성용 테이블 사용
(strategy = GenerationType.AUTO)
객체의 필드를 테이블의 컬럼과 매핑
외래키를 매핑할 때 사용
값 타입을 사용하는 곳에 표시
값 타입을 정의하는 곳에 표시
자바 enum 타입을 매핑할 때 사용
날짜 타입(java.util.Date, java.util.Calendar)을 매핑할 때 사용
JPA의 모든 동작은 엔티티 매니저를 통해서 이루어진다. 엔티티 매니저는 내부에 데이터소스를 가지고 있고, 데이터베이스에 접근할 수 있다.
EntityManager를 사용할 때 여러 쓰레드가 동시에 접근하면 동시성 문제가 발생한다. 쓰레드 간에는 EntityManager를 공유해서는 안된다.
JPA의 모든 데이터 변경은 트랜잭션 안에서 실행
@PersistenceContext
private EntityManager em;
@Autowired
private EntityManager em;
@PersistenceContext를 통해 주입해야 한다.
You shouldn't use @Autowired. "@PersistenceContext" takes care to create a unique EntityManager for every thread.
DB 테이블에 대응하는 하나의 클래스
@Entity 가 붙은 클래스는 JPA가 관리하며, DB의 테이블과 자바 클래스가 매핑이 된다.
엔티티의 생명주기

엔티티를 영구 저장하는 환경
엔티티 매니저를 통해서 영속성 컨텍스트에 접근
__특징
Fulsh
영속성 컨텍스트의 변경내용을 데이터베이스에 반영
쓰기 지연 SQL 저장소의 쿼리를 데이터베이스에 전송

테이블은 외래 키로 조인을 사용해서 연관된 테이블을 찾는다.
객체는 참조를 사용해서 연관된 객체를 찾는다.

연관관계의 주인
외래 키가 있는 곳이 주인
외래키가 무조건 __N(多)
예시1-Team:Member=1:N
@Entity
public class Member {
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "TEAM_ID")
private Team team;
}
@Entity
public class Team {
@OneToMany(mappedBy = "team")
List<Member> members = new ArrayList<Member>();
}
-----------------------------------------------------------
예시2-Member:Order=1:N
@Entity
public class Member {
@OneToMany(mappedBy = "member")
private List<Order> orders = new ArrayList<>();
}
@Entity
public class Order {
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn
private Member member;
}
__🔅양방향 연관관계에서 필수로 해야되는 것🔆
1. 연관관계 주인 설정 -> @OneToMany(mappedBy = "~")
2. @~ToOne -> fetch = FetchType.LAZY
3. 연관관계 편의 메서드
컬럼명을 직접 지정할 게 아니면 생략 가능
연관관계 주인에 값을 입력해야 SQL Table에 값이 입력된다.
Team team = new Team();
team.setName("TeamA");
em.persist(team);
Member member = new Member();
member.setName("member1");
member.setTeam(team); <-연관관계 주인에 값 설정
team.getMembers().add(member); <-SQL Table에는 영향이 없음
em.persist(member);
순수 객체 상태를 고려해서 항상 양쪽에 값을 설정하자 => 연관관계 편의 메서드
문제
관계형 데이터베이스는 정규화된 테이블 2개로 다대다 관계를 표현할 수 없음
다대다를 쓰면 JPA가 연결테이블을 알아서 만들지만 다른 데이터가 들어올 수 없음 -> 하지만 다른 데이터가 들어올일이 생김
연결테이블이 숨겨져 있기 때문에 예상하지 못한 쿼리들이 나간다.
해결
반드시 연결테이블을 추가해서 일대다, 다대일 관계로 풀어내야함
연관관계 주인이 외래키를 가짐
연관관계의 주인을 누구로 할 것인가?
엑세스를 많이 할 곳 or N(多)이 될 수도 있는 곳
모든 연관관계는 지연로딩으로 설정
실무에서 즉시 로딩 사용 절대X
즉시 로딩은 JPQL에서 N+1 문제를 일으킨다. 조인이 많아지면 예상하지 못한 쿼리가 나간다.
지연 로딩 = 우선 프록시 객체를 만들고 실제 값이 필요할 때 DB에 쿼리를 날리는 방식
@~ToOne(OneToOne, ManyToOne) 관계는 기본이 즉시로딩 -> LAZY로 설정
@OneToMany, @ManyToMany는 기본이 지연 로딩
@ManyToOne(fetch = FetchType.LAZY)
dtype이라는 컬럼명이 생긴다. 부모에 있다.
dtype 컬럼에 들어가는 기본값은 엔티티이름(=클래스이름)인데 M으로 바꿀 수 있다.
애플리케이션 로딩 시점에 자동으로 테이블 생성 -> 내가 DB에 테이블을 만들 필요가 없다.
옵션
cascade=CascadeType.XXXXX
엔티티를 영속화할 때 연관된 엔티티도 함께 영속화하는 편리함을 제공
오직 하나의 부모가 자식들을 관리할 때 쓰면 유용
저장
em.persist();
변경
변경감지 사용
트랜잭션 안에서 엔티티를 다시 조회, 변경할 값 선택 -> 트랜잭션 커밋 시점에 변경 감지
삭제
em.remove();
단건 조회
em.find(em.find(Member.class, id);
전체 조회
em.createQuery("select m from Member m", Member.class)
.getResultList();
카운트
em.createQuery("select count (m) from Member m", Long.class)
.getSingleResult();
특징
[JPQL]
select m from Member m join fetch m.team
->변환
[SQL]
SELECT M.*, T.* FROM MEMBER M INNER JOIN TEAM T ON M.TEAM_ID=T.ID
페치 조인의 한계