BE전문가 프로젝트

객체지향 쿼리 언어 본문

JPA

객체지향 쿼리 언어

원호보고서 2022. 11. 6. 18:17

JPA의 쿼리 방식

  • JPQL
  • QueryDSL
  • JPA Criteria
  • 네이티브 SQL
  • JDBC API 직접 사용, MyBatis, SpringJdbcTemplate 함께 사용

JPQL과 QueryDSL자바 코드로 작성하여 JPQL을 빌드해주는 제네레이터클래스이다.

 

JPQL 소개

  • 가장 단순한 조회 방법(Entity.find() -> 객체 그래프 탐색 a.getB().getC())
  • JPA를 사용하면 엔티티 객체를 중심으로 개발
  • 문제는 검색 쿼리
  • 검색을 할 떄도 테이블이 아닌 엔티티 객체를 대상으로 검색
  • 모든 DB데이털르 객체로 변환해서 검색하는 것은 불가능
  • 애플리케이션이 필요한 데이터만 DB에서 불러오려면 결국 검색 조건이 포함된  SQL이 필요

이런 문제들을 해결하기 위해 나온 것이 JPQL이다.

  • JPA는 SQL을 추상화한 JPQL이라는 객체 지향 쿼리 언어를 제공
  • SQL과 문법 유사, SELECT, FROM, WHERE, GROUP BY, HAVING, JOIN 지원
  • JPQL은 엔티티 객체를 대상으로 쿼리
  • SQL은 데이터베이스 테이블을 대상으로 쿼리
  • SQL을 추상화해서 특정 테이터베이스 SQL에 의존X
  • JPQL을 한마디로 정의하면 객체 지향 SQL

 

Criteria

  • JPQL의 경우 문자열로 구성되어 있기 때문에 동적 쿼리를 작성하는 것에 어려움이 있음
  • 문자가 아닌 자바코드로 JPQL을 작성할 수 있음
  • JPA 공식 기능
  • 단점: 너무 복잡하고 실용성이 없음
  • SQL스럽지 않은 쿼리이다.
  • 유지보수가 힘들기 때문에 실무에서는 사용 잘 안함
  • Criteria 대신 Query DSL 사용 권장
public class JPAMain {
    public static void main(String[] args) {
        EntityManagerFactory emf = Persistence.createEntityManagerFactory("hello");
        EntityManager em = emf.createEntityManager();

        EntityTransaction tx = em.getTransaction();
        tx.begin();                                     //트랜잭션 시작

        try {
            //Creiteria 사용 준비
            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();

            tx.commit();
        }catch (Exception e){
            tx.rollback();
        }finally {
            em.close();
        }
        emf.close();
    }
}

동적으로 사용할 때

//쿼리 생성
CriteriaQuery<Member> cq = query.select(m);

String userName = "kim";
if(userName != null){
	cq.where(cb.equal(m.get("username"), "kim"))
}

List<Member> resultList = em.createQuery(cq).getResultList();

 

QueryDSL 소개

  • 문자가 아닌 자바코드로 JPQL을 작성할 수 있음
  • JPQL 빌더 역할
  • 컴파일 시점에 문법 오류를 찾을 수 있음
  • 동적쿼리 작성 편함
  • 단순하고 쉬움
  • 실무 사용 권장
public class OrderRepositoryImpl implements OrderRepositoryCustom{
    
    private final JPAQueryFactory queryFactory;
    
    public OrderRepositoryImpl(EntityManager em){
        queryFactory = new JPAQueryFactory(em);
    }
    
    @Override
    public List<Order> findByAQUerydsl(orderSearch orderSearch){
        return queryFactory
                .select(order)
                .from(order)
                .join(order.member, member)
                .where(statusEq(orderSearch), memberNameEq(orderSearch))
                .fetch();
    }
    
    private BooleanExpression memberNameEq(OrderSearch orderSearch){
        return hasText(orderSearch.getMemberName()) ? member.name.eq(orderSearch.getMemberName()):null;
    }

    private BooleanExpression statusEq(OrderSearch orderSearch){
        return hasText(orderSearch.getOrderStatus()) ? member.name.eq(orderSearch.getOrderStatus()):null;
    }
}

 

네이티브 SQL 소개

  • JPA가 제공하는 SQL을 직접 사용하는 기능
  • JPQL로 해결할 수 없는 특정 데이터베이스에 의존적인 기능
  • 예) 오라클 CONNECT BY, 특정 DB만 사용하는 SQL 힌트
em.createNativeQuery("select MEMBER_ID, city, street from MEMBER").getResultList();

 

JDBC 직접 사용, SpringJdbcTemplate 등

  • JPA를 사용하면서 JDBC 커넥션을 직접 사용하거나, Spring JdbcTemplate, Mybatis 등을 함께 사용 가능
  • 단 영속성 컨텍스트를 적절한 시점에 강제로 플러시 필요
  • JPA를 우회해서 SQL을 실행하기 직전에 영속성 컨텍스트 수동 플러시

'JPA' 카테고리의 다른 글

프로젝션  (0) 2022.11.06
JPQL(Java Persistence Query Language)  (0) 2022.11.06
값 타입 컬렉션  (0) 2022.11.02
값 타입의 비교  (0) 2022.11.02
값 타입과 불변 객체  (0) 2022.11.02
Comments