Hibernate를 자바 표준 명세서로 만든게 JPA이며 명세서이기 때문에 인터페이스로 구성되어있다.
Insert를 한다고 가정하면, DAO에서 Entity Object를 JPA에 넘겨주고 JPA는 이를 분석해서 SQL insert 쿼리를 만들고 JDBC API를 사용해서 DB에 보낸다.
Select를 한다고 가정하면, DAO의 메소드 명을 JPA가 분석해서 SQL select 쿼리를 만들고 JDBC API를 사용해서 DB에 보내고 result를 매핑해준다.
1. 유지보수에 좋다.
DB를 마치 자바 컬렉션처럼 사용할 수 있다. 기존의 Mapper 방식처럼 필드를 수정하면 관련된 모든 SQL도 수정해야하는 상황에서 SQL은 JPA가 맡아줌으로써 의존성이 낮아진다.
2. SQL 쿼리 구조를 고려하지 않아도 된다
객체의 상속관계로 복잡한 쿼리구조를 가져도 JPA가 쿼리문을 만들어준다. -> 패러다임이 안 맞는 부분을 JPA가 중간에서 해결해준다.
3. JPA를 통해서 가져온 Entity는 믿을 수 있다
지연로딩 기능을 이용해 JPA를 통해 가져온 Entity는 proxy 객체이며 실제 객체를 조회해서 사용할 시점에 DB 쿼리가 나가서 데이터가 채워진다. 그러므로 가져온 객체를 자유롭게 그래프 탐색을 할 수 있다.
4. 복잡한 SQL도 JPQL로 대체할 수 있다.
JPQL은 객체를 대상으로하는 객체 지향 쿼리로 SQL의 JOIN과 같은 복잡한 코드를 대체할 수 있다.
한 트랜잭션내 엔티티의 변경 감지(dirty checking)를 통해서 필드 변경 내역을
자동으로 DB에 전송해주기 때문에 유지보수에 큰 장점이 있다.
String userId = "100";
User userA = jpa.find(User.class, userId);
User userB = jpa.find(User.class, userId);
위의 코드에서 userA는와 userB는 동일한 엔티티를 가르킨다. JPA는 동일한 트랜잭션에서 조회한 엔티티는 같음을 보장한다.
userA는 SQL 쿼리가 날라가서 객체를 가져오지만 userB는 userA가 들어있는 1차 캐시에서 가져오므로 동일하다.
@PersistenceContext
EntityManager em
transaction.begin();
em.persist(userA);
em.persist(userB);
em.persist(userC);
transaction.commit();
위의 코드에서 JPA는 commit이 되는 시점에 모아두었던 INSERT SQL을 DB로 보낸다.