간단하게 JPQL에 대해서 보자

JPQL은 좀더 복잡한 검색 방법에 대해 나온 쿼리 언어이다.
우리는 ORM을 사용하면 데이터베이스 테이블이 아닌 엔티티 객체를 대상으로 개발하므로 검색도 테이블이 대상이 아닌 객체를 대상으로 하는 방법이 필요 해서 나온 언어이다.

여기서 중요한 것은 데이터베이스를 대상으로 하는 것이 아니라 객체를 대상으로 하는 방식이다.

JPQL은 일반 네이티브 Sql과 비슷하다. 몇 가지만 다르고 거의 비슷한 문법을 가지고 있어 Sql을 조금할 줄 안다면 이해가 더 빠를 것 이다.

JPQL을 도와주는 빌더들이 존재한다.
1. Criteria 쿼리
2. Query Dsl

Criteria 쿼리는 Jpa에서 공식적으로 지원하는 빌더이고 QueryDsl 은 공식적으로 지원하지는 않지만 훨씬 좋다.
QueryDsl을 더 선호하는 사람들이 많다.

JPQL의 기본 문법은 아래와 같다.

select
 select 
 from
 [where]
 [groupby]
 [having]
 [orderby]

일반 sql문과 흡사하다. update와 delete도 비슷하다. insert를 얘기 하지 않은 이유는 없기때문이다. EntityManager.persist() 메소드를 사용하면 되므로 없다.

select

SELECT m FROM Member AS m where m.username = 'wonwoo'

대소문자 구분
엔티티와 속성은 대소문자를 구분한다. Member, username은 대소문자를 구분한다. 하지만 키워드 같은 경우에는 구분하지 않는다. (select, FROM, where)

엔티티 이름
JPQL에서 사용한 Member는 클래스 명이 아니라 엔티티명이다. 엔티티명은 @Entity(name=Member) 로 지정 가능하고 만약 지정 하지 않을 경우에는 클래스명을 기본값으로 사용한다.

별칭 필수
위의 Member As m 을 보면 Member에 m이라는 별칭을 주었는데 JPQL에서는 별칭을 필수로 작성 해야된다. 예를 들어 select username FROM Member m 이라고 하면 에러가 발생한다.
select m.username from Member m 으로 사용해야 한다. (AS는 생략 가능하다)

얼추 설명은 다 된거 같고 소스를 보자.
persistence.xml 파일이다.

<?xml version="1.0" encoding="UTF-8" ?>
<persistence xmlns="http://xmlns.jcp.org/xml/ns/persistence" version="2.1">
    <persistence-unit name="jpabook">
        <properties>
            <!-- 필수 속성 -->
            <property name="javax.persistence.jdbc.driver" value="org.h2.Driver"/>
            <property name="javax.persistence.jdbc.user" value="sa"/>
            <property name="javax.persistence.jdbc.password" value=""/>
            <property name="javax.persistence.jdbc.url" value="jdbc:h2:tcp://localhost/~/test"/>
            <property name="hibernate.dialect" value="org.hibernate.dialect.H2Dialect" />

            <!-- 옵션 -->
            <property name="hibernate.show_sql" value="true" />
            <property name="hibernate.format_sql" value="true" />
            <property name="hibernate.use_sql_comments" value="true" />
            <property name="hibernate.id.new_generator_mappings" value="true" />

            <!-- 테이블 자동 생성 -->
            <property name="hibernate.hbm2ddl.auto" value="create" />
        </properties>
    </persistence-unit>
</persistence>

일단 Member의 엔티티이다.

@Entity
@Data
public class Member {

  @Id
  @GeneratedValue
  private Long id;

  private String name;

  private String email;

  @ManyToOne(fetch = FetchType.LAZY)
  @JoinColumn(name = "TEAM_ID")
  private Team team;

}

다음엔 팀 엔티티 이다.

@Entity
@Data
public class Team {

  @Id
  @GeneratedValue
  private Long id;

  private String name;

  @OneToMany(mappedBy = "team")
  private List<Member> members = new ArrayList<>();
}

다음엔 메인 소스이다.

  static EntityManagerFactory entityManagerFactory = Persistence.createEntityManagerFactory("jpabook");

  public static void main(String[] args) {
    EntityManager entityManager = entityManagerFactory.createEntityManager();

    EntityTransaction transaction = entityManager.getTransaction();

    try {
      transaction.begin(); 
      save(entityManager);
      find(entityManager);
      transaction.commit();
    } catch (Exception e) {
      System.out.println(e);
      transaction.rollback();
    } finally {
      entityManager.close();
    }

    entityManagerFactory.close();
  }

  private static void find(EntityManager entityManager) {
    //객체를 탐색하는 것이다.
    TypedQuery<Member> query =
      entityManager.createQuery("select m from Member m", Member.class);
    System.out.println(
      query.getResultList()
        .stream()
      .map(i -> i.toString())
      .collect(joining("\n"))
    );
  }


  private static void save(EntityManager entityManager) {

    Team team = new Team();
    team.setName("team1");
    Team team1 = new Team();
    team1.setName("team2");

    Member member = new Member();
    member.setName("wonwoo");
    member.setEmail("test@test.com");
    member.setTeam(team);

    Member member1 = new Member();
    member1.setName("wonwoo2");
    member1.setEmail("test2@test.com");
    member1.setTeam(team);

    Member member2 = new Member();
    member2.setName("kevin");
    member2.setEmail("kevin@test.com");
    member2.setTeam(team1);

    entityManager.persist(team);
    entityManager.persist(team1);

    entityManager.persist(member);
    entityManager.persist(member1);
    entityManager.persist(member2);
  }

나머지는 그냥 입력하는 것이고 find함수를 보자
문자열로 된 select m from Member m 가 보일 것이다.
실행을 시키면 원하는 값이 출력 될 것이다.

조인은 다음과 같이 하면 된다.

TypedQuery<Member> memberQuery =
  entityManager.createQuery("select m from Member m inner join m.team t where t.id = 1", Member.class);
String str = memberQuery.getResultList()
  .stream()
  .map(i -> i.toString())
  .collect(joining("\n"));
System.out.println(str);

내부 조인, 외부 조인, 세타 조인, 페치 조인 등 여러 조인들은 지원한다.
이것들은 나중에 다시 알아 보도록하고, 일단 JPQL의 개념만 잡도록 하자.
이것으로 JPQL의 기본 개념정도 잡았다.

출처 : 자바 ORM 표준 JPA 프로그래밍 (김영한)