
JPA(Java Persistence API)
- Java 진영에서 ORM(Object-Relational Mapping) 기술 표준으로 사용하는 인터페이스
- Java 어플리케이션에서 RDB에 대한 데이터 액세스를 지원하는 방식을 정의한 API
- JPA는 인터페이스로 정의되어 있기때문에 실제 RDB와의 연동을 위해서는 Hibernate, EclipseLink, OpenJPA 등의 JPA Provider(JPA 구현체)가 필요하다.
장점
- JPA는 매핑된 관계를 이용해서 SQL을 생성하고 실행한다. 개발자는 어떤 SQL이 실행될지 생각만하면 되고, 예측도 쉽게 할 수 있다.
- SQL아닌 객체 중심으로 개발할 수 있다. 이에 따라 생산성이 좋아지고 유지보수도 수월하다.
- ORM(Object-Relational Mapping)의 Object와 RDB간의 패러다임 불일치를 해결해준다.
JPA 동작 과정

JPA는 애플리케이션과 JDBC 사이에서 동작한다.
개발자가 JPA를 사용하면, JPA 내부에서 JDBC API를 사용하여 SQL을 호출하여 DB와 통신한다.
즉, 개발자가 직접 JDBC API를 쓰는 것이 아니다.
JPA의 성능 최적화 기능
1. 1차 캐시와 동일성(identity) 보장 - 캐싱 기능
String memberId = "100";
Member m1 = jpa.find(Member.class, memberId);
Member m2 = jpa.find(Member.class, memberId);
println(m1 == m2)
- 같은 트랜잭션 안에서는 같은 엔티티를 반환 - 약간의 조회 성능 향상
2. 트랜잭션을 지원하는 쓰기 지연(transactional write-behind) - 버퍼링 기능
transaction.begin();
em.persist(memberA);
em.persist(memberB);
em.persist(memberC);
transaction.commit();
- 트랜잭션을 commit 할 때까지 INSERT SQL을 메모리에 쌓는다.
- 이렇게 하지 않으면 DB에 INSERT Query를 날리기 위한 네트워크를 3번 타게 된다.
- JDBC Batch SQL 기능을 사용해서 한 번에 SQL을 전송한다.
- JDBC Batch를 사용하면 코드가 굉장히 지저분해진다.
- 지연 로딩 전략(Lazy Loading) 옵션을 사용한다.
3. 지연 로딩(Lazy Loading)
- 지연로딩 - 객체가 실제로 사용될 때 로딩하는 전략
memberDAO.find(memberId)
에서는 Member 객체에 대한 SELECT 쿼리만 날린다.
Team team = member.getTeam()
로 Team 객체를 가져온 후에 team.getName()처럼 실제로 team 객체를 건드릴 때 즉, 값이 실제로 필요한 시점에 JPA가 Team에 대한 SELECT 쿼리를 날린다.
- Member와 Team 객체 각각 따로 조회하기 때문에 네트워크를 2번 타게 된다.
- Member를 사용하는 경우에 대부분 Team도 같이 필요하다면 즉시 로딩을 사용한다.

- 즉시 로딩
- JOIN SQL로 한 번에 연관된 객체까지 미리 조회하는 전략
- Join을 통해 항상 연관된 모든 객체를 같이 가져온다.

- 애플리케이션 개발할 때는 모두 지연 로딩으로 설정한 후에, 성능 최적화가 필요할 때에 옵션을 변경하는 것을 추천한다.