영속성 컨텍스트에 한 번도 저장
영속성 컨텍스트에 저장되어 JPA에 관리중인 상태
em.persist() 후에 commit() 꼭 필요
한때 영속이었다가 영속성 컨텍스트에서 분리된 상태
em.detach()로 분리된 적 존재
→ 준영속 상태로 전환하려면?
em.detach(entity) : 특정 엔티티 한 것만 분리해 준영속 상태로 만듦em.lclear() : 현재 영속성 컨텍스트를 초기화함em.close() : 영속성 컨텍스트 종료영속성 컨텍스트에서 제거되어 삭제된 상태
em.find() 로 조회 시 DB를 조회하기 전에 1차 캐시에서 엔티티 찾음em.find()를 여러 번 호출해도 항상 같은 객체 반환==비교로 동일성 보장받을 수 있음Member a = em.find(Member.class, "member1");
Member b = em.find(Member.class, "member1");
System.out.println(a == b); // true (동일 객체)
em.persist() 호출 시DB에 즉시 SQL을 보내지 않고 저장소에 적재해둠em.commit() 이 실행되어야 DB에 전달됨1차 캐시에 저장된 엔티티들 중 변경된 내용을 찾아 쓰기 지연 SQL 저장소에 모여있던 SQL문을 DB에 전송해 반영함
일반적으로 flush는 트랜잭션 커밋 시 자동 호출되지만 JPQL 쿼리 실행 시에도 자동 flush가 일어남
flush 모드를 선택할 수도 있음 FlushModeType.AUTO/COMMIT 둘 중 선택 가능
| @Table | 엔티티에 매핑될 테이블 이름이나 스키마 지정 |
|---|---|
| @Column | 필드와 매핑될 테이블의 컬럼을 지정하거나 DDL 제약조건 설정 가능 |
| @Enumerated | enum 타입 필드 매핑에 사용 |
| @Temporal | 날짜, 시간 등의 매핑에 사용 |
| @Lob | BLOB/CLOB와 같은 큰 바이너리, 텍스트 데이터를 매핑할 때 사용 |
| @Transient | 특정 필드를 DB에 아예 저장하도록 지정 |
| @GeneratedValue | 자동으로 +1씩 지정하도록 하기 위함 |
| 주로 id에서 많이 사용 |
객체 연관관계를 매핑하는 기본 방법은 단방향 관계를 만드는 것
@ManyToOne , @OneToMany 를 사용해 매핑함
// Member 엔티티 (회원)
@Entity
public class Member {
@Id @GeneratedValue
private Long id;
private String username;
@ManyToOne
@JoinColumn(name = "TEAM_ID") // MEMBER 테이블의 FK 컬럼
private Team team;
...
}
// Team 엔티티 (팀)
@Entity
public class Team {
@Id @GeneratedValue
private Long id;
private String name;
...
}
// 팀 저장
Team team = new Team();
team.setName("TeamA");
em.persist(team);
// 회원 저장 (팀 연관관계 설정)
Member member = new Member();
member.setName("member1");
member.setTeam(team); // Team 객체 참조 저장
em.persist(member);
// 회원 조회 후 팀 접근
Member findMember = em.find(Member.class, member.getId());
Team findTeam = findMember.getTeam(); // 참조를 통해 팀 조회
System.out.println(findTeam.getName()); // "TeamA"
// Team 엔티티에 회원 목록 추가 (양방향)
@OneToMany(mappedBy = "team")
private List<Member> members = new ArrayList<>();
mappedBy가 없는 쪽이 주인임mappedBy 속성을 지정해 매핑만 설정함Member.team 필드 값이 변경될 때만 TEAM_ID가 업데이트 되며, Team.members 컬렉션 쪽은 단순 조회용으로 사용Team team = new Team();
team.setName("TeamA");
em.persist(team);
Member member = new Member();
member.setName("member1");
// 역방향(주인이 아닌 방향)으로만 연관관계 설정
team.getMembers().add(member);
em.persist(member);
→ 주인이 아닌 방향으로 설정하면 결국 MEMBER.TEAM_ID에는 NULL이 들어감
→ 주인 방향으로 설정해야 함
@ManyToOne 필드를 두는 것이 일반적// 다대일 양방향 매핑 예시
class Member {
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "TEAM_ID")
private Team team;
...
}
class Team {
@OneToMany(mappedBy = "team")
private List<Member> members = new ArrayList<>();
...
}
@OneToMany 를 단방향으로 사용하면 중간에 조인 테이블이 만들어짐@JoinColumn 으로 FK 컬럼을 지정해야 함@ManyToMany 애노테이션을 제공하며, 이 경우 연결 테이블을 자동으로 관리. 하지만 실무에선 거의 사용하지 않음자바 객체는 상속 관계가 있지만 관계형 DB에는 상속이라는 개념이 없음
이를 대응하기위해 슈퍼타입(부모), 서브타입(자식) 모델링으로 RDB에서 상속 구조 구현
슈퍼타입과 서브타입 각각 테이블을 만들어 조인하여 조회
@Inheritance(strategy = InheritanceType.JOINED) 지정@DiscriminatorColumn(name="DTYPE") 을 적어 차별화 컬럼을 생성하면 각 레코드가 어떤 타입인지 식별 가능한 테이블에 모든 클래스를 저장, 구분 컬럼으로 타입 구분
InheritanceType.SINGLE_TABLE 만 지정하면 됨각 구체 클래스마다 자체 테이블 만듦
InheritanceType.TABLE_PER_CLASS 만 적으면 됨공통 매핑 정보를 여러 엔티티에서 사용해야할 때는 @MappedSuperclass 애노테이션 사용
BaseEntitty 라는 추상 클래스를 만들고 여기에 필드를 정의하고 @MappedSuperclass 로 지정BaseEntity 를 상속받기만 해도 BaseEntity 의 필드들이 각 엔티티 테이블의 컬럼으로 포함됨@MappedSuperclass 는 엔티티가 아니기에 DB 테이블과 매핑되지 않고, 별도 조회도 불가능. 그냥 공통 필드를 전달하는 것 뿐