JPA
연관관계
### 단반향 연관관계
CREATE TABLE MEMBER (
ID BIGINT(20) NOT NULL AUTO_INCREMENT,
TEAM_ID BIGINT(20),
NAME VARCHAR(20),
PRIMARY KEY (ID)
)
CREATE TABLE TEAM (
ID BIGINT(20) NOT NULL AUTO_INCREMENT,
NAME VARCHAR(20),
PRIMARY KEY (ID)
)
ALTER TABLE MEMBER ADD CONSTRAINT FK_MEMBER_TEAM FOREIGN KEY (ID) REFERENCES TEAM
@Entity
public class Member {
@Id
@Column(name = "ID")
private Long id;
@Column(name = "NAME")
private String name;
@ManyToOne
@JoinColumn(name="ID")
private Team team;
}
@Entity
public class Team {
@Id
@Column(name="ID")
private Long id;
@Column(name="NAME")
private String name;
}
### 양방향 연관관계 ### 연관관계의 주인 ### 양방향 연관관계 저장 ### 양방향 연관관계 주의점
N+1
- 전체 조회 및 N 번 조회
- Join Fetch (Inner Join)
- @EntityGraph (Outer Join)
OSIV
- OSIV(Open Session In View)는 영속성 컨텍스트를 뷰까지 열어둔다는 뜻
- 과거 OSIV : 요청 당 트랜잭션
- OSIV의 핵심은 뷰에서도 지연 로딩이 가능하도록 하는 것
- 클라이언트의 요청이 들어오자마자 서블릿 필터나 스프링 인터셉터에서 트랜잭션을 시작하고 요청이 끝날 때 트랜잭션도 끝내는 것
- 요청 당 트랜잭션 방식의 OSIV 문제점
- 프리젠텐이션 계층에서 수정된 내용이 데이터베이스까지 변경
- 해결법
- 엔티티를 읽기 전용 인터페이스로 제공
- 엔티티 래핑
- DTO만 반환
- 스프링 OSIV : 비즈니스 계층 트랜잭션
- 스프링 프레임워크가 제공하는 OSIV 라이브러리
- 스프링 OSIV
- 클라이언트의 요청이 들어오면 서블릿 필터나, 스프링 인터셉터에서 영속성 컨텍스트를 생성 (트랜잭션 시작하지 않음)
- 서비스 계층에서 @Transaction로 트랜잭션을 시작할 때 1번에서 미리 생성해둔 영속성 컨텍스트를 찾아와서 트랜잭션을 시작
- 서비스 계층이 끝나면 트랜잭션을 커밋하고 영속성 컨텍스트를 플러시 (트랜잭션을 끝내지만 영속성 컨텍스트는 종료하지 않음)
- 컨트롤러와 뷰까지 영속성 컨텍스트가 유지되므로 조회한 엔티티는 영속 상태를 유지
- 서블릿 필터나, 스프링 인터셉터로 요청이 돌아오면 영속성 컨텍스트를 종료 (플러시를 호출하지 않고 바로 종료)
- 스프링 OSIV 주의사항
- 프리젠테이션 계층에서 엔티티를 수정 후 트랜잭션을 시작하는 서비스 계층을 호출하면 문제 발생
class MemberController {
public String viewMember(Long id) {
Member member = memberService.getMember(id);
member.setName("***");
memberService.biz();
return "view";
}
}
class MemberService {
@Transcactional
public void biz() {
}
}
2차 캐시
- 1차 캐시
- 영속성 컨텍스트 내부에 있음
- 엔티티 매니저로 조회하거나 변경하는 모든 엔티티는 1차 캐시에 저장
- JAP를 J2EE나 스프링 프레임워크 같은 컨테이너 위에서 실행하면 컨텍스트도 종료
- OSVI를 사용하면 요청의 시작부터 끝까지 같은 영속성 컨텍스트를 유지
- 2차 캐시
- 애플리케이션 범위의 캐시
- 분산 캐시나 클러스터링 환경의 캐시는 애플리케이션보다 더 오래 유지될 수 있음
- 2차 캐시의 동작 방식
- 영속성 컨텍스트는 엔티티가 필요한면 2차 캐시를 조회
- 2차 캐시에 엔티티가 없으면 데이터베이스를 조회
- 결과를 2차 캐시에 보관
- 2차 캐시는 자신이 보관하고 있는 엔티티를 복사해서 반환
- 2차 캐시에 저장되어 있는 엔티티를 조회하면 복사본을 만들어 반환