객체지향 쿼리
find()를 사용해서 식별자로 엔티티 하나를 조회할 수 있다.
조회한 엔티티에 객체 그래프 탐색을 사용하면 연관된 엔티티를 찾을 수 있다.
다음이 가장 단순한 조회방법이다.
- 식별자로 조회
- 객체 그래프 탐색
이 기능만으로 애플리케이션 개발은 어렵다.
좀더 복잡한 검색 방법이 필요할 수 있는데 결국 데이터는 DB에 있어서 SQL로 필요한 내용을 조회해야 한다.
하지만 ORM은 DB가 아닌 객체를 활용하기 때문에 엔티티 객체를 대상으로 조회하는 방법을 필요로 한다.
SQL이 DB테이블을 대상으로 하는 데이터 중심 쿼리라면 JPQL은 엔티티 객체를 대상으로 하는 객체지향 쿼리이다.
JPQL을 사용하면 JPA가 이를 분석하여 적절한 SQL을 만들어 DB를 조회한다.
JPA는 JPQL 뿐만 아니라 다양한 검색 방법을 제공한다
- JPQL
- Criteria
- Native SQL
- QueryDSL
- JDBC 직접 사용
1. JPQL
JPQL은 엔티티 객체를 조회하는 객체지향 쿼리이다.
JPQL은 SQL을 추상화해서 특정 DB에 의존하지 않는다.
그리고 DB 방언만 수정하면 JPQL을 변경하지 않아도 자연스럽게 DB를 변경할 수 있다.
JPQL은 SQL보다 간결하다.
엔티티 직접조회, 묵시적 조인, 다형성 지원 으로 SQL보다 코드가 간결하다.
2. Criteria
Criteria는 JPQL을 생성하는 빌더 클래스이다.
query.select(m).where() 처럼 프로그래밍 코드로 작성할수 있다는 장점이 있다.
Criteria는 문자가 아닌 코드로 JPQL을 작성하기 때문에 컴파일 시점에 오류를 발견할 수 있다.
- 동적 쿼리를 작성하기 편하다.
// Criteria 사용준비
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<Member> query = cb.createQuery(Member.class);
Root<Member> m = query.from(Member.class);
// 쿼리 생성
CriteriaQuery<Member> cq =
query.select(m).where(cb.equal(m.get("username"), "kim"));
List<Member> resultList = em.createQuery(cq).getResultList();
Criteria가 가진 장점은 많지만 모든 장점을 상쇄할 정도로 복잡하고 장황하다.
따라서 한눈에 들어오지 않는 단점이 존재.
3. QueryDSL
QueryDSL 은 Criteria 처럼 JPQL 빌더 역할을 하지만 코드기반이면서 단순하고 사용하기 쉽다.
JPAQuery query = new JPAQuery(em);
QMember member = QMember.member;
List<Member> members =
query.from(member)
.where(member.username.eq("kim"))
.list(member);
QueryDSL 은 특별한 설명없이도 충분히 이해된다, 이것 또한 쿼리 전용 클래스를 만들어야 한다.
네이티브 SQL은 JPA에서 SQL을 직접 사용할수 있는 기능을 말한다.
SQL은 지원하지만 JPQL이 지원하지 않는 기능이 있는데 그런것들을 사용할 때 쓴다.
단점은 DB가 변경되면 해당 SQL도 변경되야한다는 점이다
String sql = "SELECT ID, AGE, TEAM_ID, NAME FROM MEMBER WHERE NAME = 'kim'";
List<Member> resultList = em.createNativeQuery(sql, Member.class).getResultList();
4. Native SQL
네이티브 SQL은 em.createNativeQuery 를 사용하면 된다 나머지는 JPQL과 동일하다.
JDBC 템플릿 이나 MyBatis를 사용하는 방법은 드물지만,
JPA는 JDBC 커넥션을 획득하는 API을 미지원하므로 JPA 구현체가 제공하는 방법을 써야한다.
Session session = entityManager.unwrap(Session.class);
session.doWork(new Work() {
@Override
public void execute (Connection connection ) throws SQLException {}
});
JPA EntityManager에서 하이버네이트 Session을 구한다. 그리고 doWork 메서드를 호출하면 된다.
* 주의사항
JDBC나 마이바티스를 JPA와 함께 쓰려면 영속성 컨텍스트를 적절한 시점에 강제로 플러시 해야한다.
이런 템플릿이나 SQL Mapper는 JPA가 전혀 인식을 못해서 영속성 컨텍스트와 DB를 불일치 상태로 만들어
무결성이 훼손될수 있다.
문제 해결방법.
1. JPA를 우회해서 SQL을 실행하기 전에 영속성 컨텍스트를 수동으로 플러시하고
DB와 영속성 컨텍스트를 동기화 시켜야 한다.
2. 스프링 프레임워크의 AOP 를 활용해서 JPA를 우회해서 DB접근을 하는 메서드를 호출 할 때마다 영속성 컨텍스트를 플러시 하는 방법으로 해결할 수 있다.
'Back-End > JPA' 카테고리의 다른 글
JPA) 과거 방식의 OSIV (0) | 2022.03.13 |
---|---|
JPA) 값 타입 컬렉션 vs @OneToMany (0) | 2022.03.12 |
JPA) 영속성 전이 (0) | 2022.03.12 |
JPA) Eager, Lazy 로딩 (0) | 2022.03.12 |
JPA ) 연관관계 매핑 (0) | 2022.03.11 |