2018.11.22 T아카데미 JPA 기술세미나 참석시 기록.
JPA는 Spring Data로 실제 담당 시스템에 적용되어 사용하고 있기는 하나 기본 개념의 재정립이 절실하던 중 T아카데미에서 관련 세미나 소식이 들려왔다.
강의하시는 분이 자바 ORM 표준 JPA 프로그래밍 저자이기도 해서 바로 신청했는데 짧은 시간 내에 굉장히 유익했던 내용이었다.
실습 준비
H2 데이터베이스 설치 (http://www.h2database.com)
JPA와 모던 자바 데이터 저장 기술
객체와 관계형 데이터베이스의 차이
- 상속 객체 [상속 관계 - Table 수퍼타입 서브타입 관계]
- 연관관계
- 객체는 참조를 사용: member.getTeam()
- 테이블은 외래 키를 사용: JOIN ON M.TEAM_ID = T.TEAM_ID
- 데이터 타입
ORM?
- Object-relational mapping(객제 관계 매핑)
- 객체는 객체대로 설계
- 관계형 데이터베이스는 관계형 데이터베이스 대로 설계
- ORM 프레임워크가 중간에서 매핑
JPA는 표준 명세
- JPA는 인터페이스이고 실제로 구현된 것은 하이버네이트이다.
- SQL 중심적인 개발에서 객체 중심으로 개발
JPA의 성능 최적화 기능
- 1차 캐시와 동일성 보장
- 같은 트랜잭션 안에서는 같은 엔티티를 반환 - 약간의 조회 성능 향상
- 트랜잭션을 지원하는 쓰기 지연
- 트랜잭션을 커밋할 때까지 INSERT SQL을 모음
- JDBC BATCH SQL를 사용해서 한꺼번에 DB에 전송하고 커밋
- 지연 로딩(Lazy Loading)
- 지연 로딩 - 객체가 실제 사용될 때 로딩
- 즉시 로딩 - JOIN SQL로 한번에 연관된 객체까지 미리 조회
ORM은 객체와 RDB 두 기둥 위에 있는 기술
실습
1. H2 DB에서 테스트 테이블 생성
2. Maven 프로젝트 생성하여 jpa, h2database 라이브러리 추가
3. Main클래스와 Entity클래스를 생성
4. persistence.xml 파일을 생성하여 /resources/META-INF/ 디렉터리에 넣음
5. Main클래스에 데이터 등록 코드 작성
6. H2 DB에 실제 데이터가 등록되었는지 확인해본다.
- 엔터티 매니저 팩토리는 하나만 생성해서 애플리케이션 전체에서 공유
- 엔터티 매니저는 쓰레드 간에 공유하면 안된다. (사용하고 버려야 됨)
데이터베이스 스키마 자동 생성하기
- DDL을 애플리케이션 실행 시점에 자동 생성
- 테이블 중심 -> 객체 중심
- 데이터베이스 방언을 활용해서 데이터베이스에 맞는 적절한 DDL생성
- 이렇게 생성된 DDL은 개발 장비에서만 사용
hibernate.hbm2ddl.auto
- create: 기존 테이블 삭제 후 다시 생성 (DROP + CREATE)
- create-drop: create와 같으나 종료시점에 테이블 drop
- update: 변경분만 반영(운영에는 적용하면 안됨)
- validate: 엔터티와 테이블이 정상 매핑되었는지 확인
- none: 사용하지 않음
식별자 매핑 방법 @Id (직접 매핑)
- IDENTITY : 데이터베이스에 위임, MYSQL
- SEQUENCE: 데이터베이스 시퀀스 오브젝트 사용
권장하는 식별자 전략
- 기본키 제약 조건 : not null, 유일, 변하면 안된다.
- 미래까지 이 조건을 만족하는 자연키는 찾기 어렵다. 대리키(대체키)를 사용하자.
- 예를 들어 주민등록번호도 기본 키로 적절하지 않다.
- 권장 : Long + 대체키 + 키 생성전략 사용
연관관계의 주인과 mappedBy
- 객체의 양방향 관계는 사실 양방향 관계가 아니라 서로 다른 단방향 관계 2개다.
- 객체의 두 관계 중 하나를 주인으로 설정하고 주인 객체에서 일어나는 업데이트 동작만 실제 DB에 적용
- ‘mappedBy’ 는 주인이 아니고 조회만 되는 것
- 주인은 mappedBy 속성 사용하지 않음
- 주인이 아니면 mappedBy 속성으로 주인을 지정
- 외래 키가 있는 곳을 주인으로 정해라
- 어지간하면 단방향으로 설계를 끝내라
- 필요하면 반대쪽 객체에 mappedBy 설정만 추가해라
주인이 아닌 객체에 member객체를 추가하고 저장
외래키가 null로 들어감
주인인 객체에 team객체를 셋팅 후 저장
외래키가 저장됨
- 테이블은 외래 키 하나로 두 테이블의 연관관계를 정리
JPA 내부 구조
- 영속성 컨텍스트
- 객체를 생성한 상태(비영속 - new)
- 객체를 저장한 상태(영속 - managed)
트랜잭션을 커밋하거나 JPQL를 사용할 때 플러시가 자동으로 되나 Spring Data등 다른 라이브러리랑 섞어 쓸 때는 수동으로 .flush()메서드로 수행한다.
연관관계와 함께 지연로딩을 설정했을 때, 엔터티 매니저를 클로징한 뒤(em.close();) 조회를 시도하면 에러가 발생한다.
JPA와 객체지향 쿼리
- JPQL
- 외부에 제공하는 API는 엔터티가 아닌 별도의 dto를 만들어서 제공하는 것을 권장 (엔터티 변경 시마다 API도 변경되버려 운영에 어려움)
JPA 기반 프로젝트
- Spring Data JPA
- QueryDSL - 문자가 아닌 코드로 작성
.png)
.png)
.png)
.png)
.png)
.png)


