ORM
- Object Relational Mapping(객체 관계 매핑)
- 객체는 객체대로, RDB는 RDB 대로 설계하여 ORM 프레임워크가 중간에서 매핑
JPA
-
1차 캐시와 동일성 보장
- 같은 트랜잭션 안에서는 같은 엔티티를 반환(조회 성능 소폭 향샹)
- DB Isolation Level이 Read Commit이어도 애플리케이션에서 Repeatable Read 보장
-
트랜잭션을 지원하는 쓰기 지연(INSERT)
- 트랜잭션을 커밋할 때깢 INSERT SQL을 모음
- JDBC BATCH SQL 기능을 사용해서 한번에 SQL 전송
-
지연 로딩과 즉시 로딩
- 지연 로딩 : 객체가 실제 사용될 때 로딩
- 즉시 로딩 : JOIN SQL로 한번에 연관된 객체까지 미리 조회
영속성 Context
EntityManagerFactory emf = Persistence.createEntityManagerFactory("hello");
EntityManager em = emf.createEntityManager();
EntityTransaction tx = em.getTransaction();
tx.begin();
Member member = new Member();
member.setId(1L);
member.setName("HelloJPA");
em.persist(member);
em.detach(member);
쓰기지연
persist() 호출 순간 1차 캐시에 저장하고 commit() 호출때 한번에 처리.
엔티티 설계시 주의점
- 가급적 Setter를 사용하지 말자(변경 포인트가 너무 많아서 유지보수가 어려워짐, 대체법 찾아보기)
- 모든 연관관계는 지연로딩으로 기본 설정
- 즉시로딩(EAGER)은 예측이 어렵고, 어떤 SQL이 실행될지 추적하기 어렵다. 특히 JPQL을 실행할 때 N+1 문제가 자주 발생.
- @XToOne 관계는 기본이 즉시로딩이므로 지연로딩으로 설정해줘야 함
- 컬렉션은 필드에서 초기화
- null-safety
- 하이버네이트는 엔티티를 영속화 할 때, 컬렉션을 감싸서 하이버네이트가 제공하는 내장 컬렉션으로 변경함.
- 테이블, 컬럼명 생성 전략
- 하이버네이트 기본 구현: 엔티티의 필드명을 그대로 테이블 명으로 사용(SpringPhysicalNamingStrategy)
- 스프링 부터 신규 설정
- 카멜 케이스 -> 스네이크 케이스
- .(점) -> _(언더스코어)
- 대문자 -> 소문자
- 논리명 생성: 명시적으로 컬럼, 테이블명을 직접 적지 않으면 ImplicitNamingStrategy 사용
- 물리명 적용: 모든 논리명에 적용됨
테이블 연관관계
@ManyToOne - n:1
@OneToMany - 1:n
@JoinColumn(name = "외래키 필드 이름")
참고
DB Isolation Level
트랜잭션 격리 수준
동시에 여러 트랜잭션이 처리될 때, 트랜잭션끼리 얼마나 서로 고립되어 있는지를 나타내는 것
- READ UNCOMMITTED
- 어떤 트랜잭션의 변경내용이 COMMIT이나 ROLLBACK과 상관없이 다른 트랜잭션에서 보여진다
- READ COMMITTED
- 어떤 트랜잭션의 변경 내용이 COMMIT 되어야만 다른 트랜잭션에서 조회할 수 있다
- REPEATABLE READ
- 트랜잭션이 시작되기 전에 커밋된 내용에 대해서만 조회할 수 있는 격리수준
- SERIALIZABLE
- 트랜잭션에서 일관성이 없는 데이터를 허용하도록 하는 수준을 의미