Java Persistence API : 자바 진영의 ORM 기술 표준
📢ORM이란
JDBC API : 자바를 이용한 데이터베이스 접속 (Connection), SQL문의 실행, 실행결과 데이터 핸들링을 제공하는 방법과 절차에 관한 규약이다.
MemberDAO에서 객체를 저장하기 위해서 Member 객체를 JPA에 넘긴다.
그럼 JPA가 Member 객체를 분석 후 적절한 INSERT query를 생성한다.
그 후 JDBC API를 사용하여 INSERT query를 DB에 보낸다.
DB에서 결과를 받는다.
Member의 pk값 (id)만 JPA에 넘기면
JPA가 Member 객체를 분석해 적절한 SELECT query를 만들어낸다.
이를 JDBC API를 사용하여 쿼리를 DB에 보낸 뒤 결과를 반환 받는다.
결과로 받은 ResultSet을 객체에 매핑해준다.
👉 이 번잡한 과정이 코드 한줄find(id)
만으로 실행된다.
📌저장, 조회 과정에서 가장 눈여겨 봐야할 점은 JPA의 패러다임의 불일치 해결
능력이다
EJB
(과거의 자바 표준 ORM) : 성능이 매우 구림 👉
EJB에 열받은 개발자가하이버네이트 (오픈소스)
를 개발함 👉
자바 진영에서 하이버네이트를 만든 개발자를 불러 이와 비슷한JPA(자바 표준)
을 만들게 됨
JPA의 코드를 들여다 보면 인터페이스밖에 없다 (껍데기 스펙의 모음)
JPA의 스펙을 구현한구현체
가 여러 개 존재한다. (하이버네이트, EclipseLink, DataNucleus)
이 중 대부분이하이버네이트 구현체
를 사용한다.
jpa.persist(member)
Member member = jpa.find(memberId)
member.setName(“변경할 이름”)
jpa.remove(member)
이미 CRUD에 대한 코드가 만들어져있다.
특히setName
메소드를 사용하면 그냥 "변경할 이름"으로 이름이 변경되어 DB UPDATE query가 나간다.
기존에는 객체의 필드 하나만 추가, 수정하게 되면 모든 쿼리문들도 같이 수정해줘야 하는 번거로움이 있었다.
JPA를 사용하게 되면 객체에 필드 하나만 추가하면 된다. 쿼리문을 따로 수정해줄 필요가 없다.
개발자가 Album객체를 저장하기 위해
persist(album);
메소드를 사용하면
JPA는ITEM
,ALBUM
에 대한 INSERT QUERY를 쪼개서 만든다
개발자는 Album을 pk로 조회하기 위해
find(Album.class, albumId)
메소드를 사용하면
ITEM
,ALBUM
테이블을 JOIN한 테이블로 Item, Album 객체에 데이터를 넣어준다.
member에 team와의 연관관계를 세팅(
setTeam
)하고 저장(persist
)한다.
memberId로 member를
find
하여 얻은 Member 객체는 연관관계를 가진 Team객체를 참조(getTeam
)할 수 있다.
👉 마치 Java Collection에 넣었던 것 처럼 참조할 수 있다.
이제 JPA와 함께라면 Member 객체로 Team객체를 탐색하듯
객체 그래프 탐색
을 자유롭게 활용할 수 있다.
👉지연로딩
을 통해member.getTeam()
으로 Team객체를 참조하는 시점에 SQL문이 생성되어 member와 연관관계가 있는 team의 정보를 가져온다.
JPA는 같은 트랜잭션에서 조회한 엔티티는 같음을 보장한다.
두 개의 서로 다른 계층 사이의 중간 계층에서는
버퍼링(모아서 쏘기)
,캐싱(읽기)
기능이 가능하다.
(cpu와 memory, 객체와 관계형 DB사이의 JPA, … )
📢캐싱
기능 : 같은 트랜잭션 안에서는 같은 엔티티를 반환한다. (약간의 조회 성능 향상)
Member m1
: JPA가 SELECT query를 날려서 DB로부터 받은 데이터를 담고 있다.
Member m2
: 같은 pk값으로find
한 경우, JPA는 메모리에 있는Member m1
을 그대로 반환해준다
(캐싱을 한다)
👉 결과적으로 SQL이 한번만 실행된다.
👉 굉장히 짧은 시간동안의 캐싱이다. (하나의 트랜잭션이 시작후 끝날 떄 까지만 적용할 수 있는 캐싱 방법)
📢버퍼링
기능 : JDBC BATCH SQL을 통한 JPA의 쓰기 지연
기능이다
memberA, memberB, memberC
를 메모리에 쌓아 둔 뒤commit
되는 순간 한번에 INSERT query를 보낸다.
📢지연 로딩 : 객체가 실제 사용될 떄 로딩
memberDAO.find(memberId);
를 통해 Member 객체의 정보만 가져온다.
이 때, Team 객체는 아직 빈 껍데기 뿐인 프록시 객체이다.
Member 객체와 연관관계에 있는 Team 객체의 name속성을 건들 시점(team.getName();
) 에서 JPA가 Team에 대한 SELECT query를 날려 Team 객체에 데이터를 채워준다.
👉 지연로딩의 문제 : query가 여러 번 나간다.
📢즉시 로딩 : JOIN SQL로 한번에 연관된 객체까지 미리 조회
쿼리가 여러 번 나가는
지연 로딩
의 문제점을 보완한다.
보통 개발할 때, Member 객체와 함께 Team 객체를 사용하기 때문에memberDAO.find(memberId);
를 통해 Member와 Team 정보를 한번에 가져온다.
👉 JPA의 옵션을 바꾸면지연 로딩
에서즉시 로딩
으로 변경할 수 있다.
ORM은 객체
와 관계형 DB
두 기둥위에 있는 기술이다.
객체
는 다른 언어로 변경될 수 있지만관계형 DB
는 더 오래유지된다
👉 관계형 DB에 대한 공부가 중요하다