상속
테이블이 위와 같이 Album,Movie,Book이 Item을 상속하는 관계에 있다고 가정했을때
저장 개발자 : jpa.persist(album); JPA : INSERT INTO ITEM... INSERT INTO ALBUM...
조회 개발자 : Album album = jpa.find(Album.class,albumId); JPA : SELECT I.*, A.* FROM ITEM I JOIN ALBUM A ON I.ITEM_ID = A.ITEM_ID
연관관계
객체의 참조로 연관관계를 저장이 가능하다.
Member에 Team Entity가 포함되어 있는 경우 Member객체에 Team을 setting해주고 저장하면 Member와 Team을 연관지어 같이 저장한다. Member member = new Member();Team team = new Team(); member.setTeam(team); jpa.persist(member);
객체 그래프 탐색
class MemeberService{
public void process(){
/*SQL을 구현한 DAO에서 가져온 Member객체에서 Team 조회*/
Member member1 = memberDAO.find(memberId);
member.getTeam();
/*JPA를 통해 조회한 Memeber객체에 Team 조회*/
Member member2 = jpa.find(Member.class,memberId);
member2.getTeam();
}
}
SQL로 구현한 결과로 가져온 Member에서는 SQL를 확인하기 전까지, Member에 Team을 포함한 정보를 가져왔는지 알 수 없기 때문에, member.getTeam()에서 Nullpoint Error가 발생 할 가능성이 있다.
JPA를 사용시 객체간 연관관계를 파악하여, Team과 Member가 연관되어 있을경우 Eagar Loading(즉시 로딩)을 통해 Member와 Team정보를 조인하여 한번에 결과를 조회하여 Member에 연관된 Team정보를 조회 할 수 있다. Lazy Loading(지연 로딩)을 통해 Member 정보를 조회한 후 Member에서 Team정보를 가져올때 Member와 연관된 Team정보를 조회함으로써, Member와 연관된 Team 정보를 조회 할 수 있다.
String memberId = "100";
Member member1 = jpa.find(Member.class, memberId); //SQL 쿼리를 통한 조회
Mebmer member2 = jpa.find(Member.class, memberId); //1차 캐쉬에서 데이터 조회
println(member1 == member2); // 같음(true)
같은 트랜잭션 안에서 동일한 객체 조회를 2번 조회했음에도 SQL은 첫번째 조회에만 실행하고 두번째 조회한 데이터는 1차 캐쉬에 있는 정보를 가져옴으로써 SQL을 1번 실행한다.
트랜잭션을 지원하는 쓰기지연(Transactional write-behind)
INSERT
/* 트랜잭션을 커밋할 때까지 INSERT SQL을 모아뒀다가 한번에 SQL을 전송 */
transaction.begin();
em.persist(memberA);
em.persist(memberB);
em.persist(memberC);
// 여기까지 INSERT SQL을 데이터베이스에 보내지 않는다.
// 커밋하는 순간 데이터베이스에 INSERT SQL을 모아서 보낸다.
transaction.commit(); [트랜잭션] 커밋
데이터 저장(persist) 실행시 바로 SQL문을 DB로 전송하는것이 아니라 트랜잭션 commit과 동시에 SQL문을 DB로 전송함으로써 한번의 네트워크로 데이터 저장을 실행한다.
UPDATE
/* UPDATE,DELETE로 인한 로우(ROW)락 시간 최소화*/
trasaction.begin();
changeMember(memberA);
deleteMember(memberB);
비즈니스_로직_수행(); // 비즈니스 로직 수행 동안 DB 로우 락이 걸리지 않는다.
/* 트랜잭션 커밋 하는 순간 UPDATE, DELETE SQL을 실행 */
transaction.commit();
UPDATE, DELETE로 인한 시간 최소화 및 트랜잭션 커밋과 동시에 UPDATE, DELETE SQL을 실행
지연 로딩(Lazy Loading)
// 지연로딩
MEMBER member = meberDAO.find(memberId); SELECT * FROM MEMBER
Team team = member.getTeam();
String teamName = team.getName(); SELECT * FROM TEAM
// 즉시로딩
Member member = memberDAO.find(memberID); SELECT M.*. T.*
Team team = member.getTeam(); FROM MEMBER
String teamName = team.getName(); JOIN TEAM
Lazy Loading(지연 로딩)은 객체가 실제 사용될때 해당 데이터를 DB에서 가져오는 방식으로 실제 사용될때 가져와서 지연 로딩이라고 한다.
Eagar Loading(즉시 로딩)은 JOIN SQL을 통해 한번에 연관된 객체까지 미리 조회하여 데이터를 DB에서 가져오는 방식이다.
실제 업무에서는 Lazy Loading을 많이 사용하는데, 객체간 얼마나 연관되어 있는지 알 수 없기 때문에, Eagar Loading을 사용시 불필요한 SQL JOIN으로 인해 성능 저하가 발생할 수 있기 때문이다.
데이터 접근 추상화와 벤더 독립성
표준
JPA 동작 과정
JPA는 Java 어플리케이션과 JDBC 사이에서 동작한다.
개발자가 JPA를 사용시, JPA 내부에서 JDBC API를 사용하여 SQL를 호출하여 DB에 SQL문을 전달하고 결과를 받아 Java 어플리케이션으로 전달해 준다.