JPQL
SQL을 추상화한 객체 지향 쿼리 언어로 엔티티 객체 중심으로 쿼리를 작성할 수 있다.
- SQL은 데이터베이스 테이블을 대상으로 쿼리를 날리지만 JPQL은 엔티티 객체를 대상으로 쿼리를 날린다
- JPQL로 작성하면 결국은 SQL로 변환되어 데이터베이스에 쿼리를 날리게 된다.
JPQL 문법
em.createQuery("select m from Member m where m.age > 15", Member.class)
- Member 테이블 전체를 조회하는 JPQL 쿼리이다.
- select, from, where과 같은 키워드들은 대소문자를 구분하지 않는다.
- Member, m.age와 같이 엔티티와 속성은 대소문자를 구분하여야 한다.
- 테이블 이름이 아닌 엔티티 이름을 써야 한다.
- Member (as) m과 같이 별칭은 필수이며 as는 생략 가능함
TypeQuery, Query
Query query = em
.createQuery("select m from Member m where m.age = 15");
TypedQuery<Member> query1 = em
.createQuery("select m from Member m where m.age > 15", Member.class);
- 반환 타입이 명확하지 않아 createQuery에 타입을 작성하지 않으면 Query가 된다.
- 반환 타입이 명확하여 createQuery에 타입을 넣어주면 TypeQuery가 된다.
결과 값, 파라미터 바인딩
Member member = em
.createQuery("select m from Member m where m.age = 15", Member.class)
.getSingleResult();
List<Member> memberList = em
.createQuery("select m from Member m where m.age > 15", Member.class)
.getResultList();
Member memberParam = em
.createQuery("select m from Member m where m.age = :age", Member.class)
.setParameter("age", 15)
.getSingleResult();
getSingleResult
- 결과를 하나만 조회할 수 있다.
- 단 조회된 결과가 둘 이상이면 NonUniqueResultException이 발생한다.
- 그리고 결과가 하나라면 NoResultException이 발생한다.
getResultList
- 결과를 컬렉션으로 받아올 수 있다. 결과가 없으면 빈 리스트를 반환한다.
setParameter
- JPQL에 :age로 작성하고 setParameter를 통해 파라미터 바인딩이 가능하다.
- SQL 인젝션을 방지할 수 있으므로 항상 사용하자.
프로젝션(select)
엔티티 조회
List<Member> members = em.createQuery("select m from Member m where m.age > :age", Member.class)
.setParameter("age", 15)
.getResultList();
Member firstMember = members.get(0);
firstMember.setName("Dexter");
- 엔티티 프로젝션으로 엔티티를 조회한다.
- 값을 받아오면 영속성 콘텍스트에 관리되므로 인스턴스의 값을 바꿔도 아래와 같이 자동으로 update 쿼리가 날아간다.
Hibernate:
/* update
blogJpa.Member */ update
Member
set
createTime=?,
lastModifiedDate=?,
age=?,
name=?
where
member_id=?
연관관계 엔티티 조회
@Entity
public class Member extends BaseTimeEntity {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "member_id")
private Long id;
private String name;
private int age;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "team_id")
private Team team;
}
@Entity
public class Team {
@Id
@GeneratedValue
@Column(name = "team_id")
private Long id;
private String teamName;
@OneToMany(mappedBy = "team")
private List<Member> members = new ArrayList<>();
}
// Main
List<Team> resultList = em.createQuery("select m.team from Member m", Team.class)
.getResultList();
System.out.println("======================================================");
List<Team> resultList2 = em.createQuery("select t from Member m join m.team t", Team.class)
.getResultList();
Hibernate:
select
team1_.team_id as team_id1_3_,
team1_.teamName as teamName2_3_
from
Member member0_
inner join
Team team1_
on member0_.team_id=team1_.team_id
======================================================
Hibernate:
select
team1_.team_id as team_id1_3_,
team1_.teamName as teamName2_3_
from
Member member0_
inner join
Team team1_
on member0_.team_id=team1_.team_id
- 위에 방법처럼 m.team으로 바도 받아와도 실제 쿼리를 보면 join을 하는 것을 알 수 있다.
- 하지만 명시적으로 아래 방법으로 하는 게 좋다.
스칼라 타입 조회
Member member = new Member("dexter", 19, team);
em.persist(member);
List resultList = em.createQuery("select m.name, m.age from Member m")
.getResultList();
Object[] objects = (Object[]) resultList.get(0);
System.out.println("name = " + objects[0]);
System.out.println("age = " + objects[1]);
Hibernate:
/* select
m.name,
m.age
from
Member m */ select
member0_.name as col_0_0_,
member0_.age as col_1_0_
from
Member member0_
name = dexter
age = 19
- Object [] 타입으로 여러 타입 값을 받아 사용이 가능하다.
@Getter
@Setter
@NoArgsConstructor
public class MemberDto {
private String name;
private int age;
public MemberDto(String name, int age) {
this.name = name;
this.age = age;
}
}
// Main
List<MemberDto> resultList = em
.createQuery("select new blogJpa.MemberDto(m.name, m.age) from Member m", MemberDto.class)
.getResultList();
MemberDto memberDto = resultList.get(0);
System.out.println("memberDto.getName() = " + memberDto.getName());
System.out.println("memberDto.getAge() = " + memberDto.getAge());
Hibernate:
/* select
new blogJpa.MemberDto(m.name,
m.age)
from
Member m */ select
member0_.name as col_0_0_,
member0_.age as col_1_0_
from
Member member0_
memberDto.getName() = dexter
memberDto.getAge() = 19
- new 명령어를 통해 DTO에 바로 값을 담을 수도 있다.
- 하지만 패키지명을 포함한 전체 클래스명이 필요하며 생성자의 파라미터 순서가 일치하여야 한다.
'JPA' 카테고리의 다른 글
JPQL 서브쿼리, 조건식, 기본 함수 (0) | 2020.01.26 |
---|---|
JPQL 페이징, 조인과 조인 ON 절 (0) | 2020.01.25 |
JPA 연관관계 매핑 6. 영속성 전이(CASCADE)와 고아 객체 (0) | 2020.01.23 |
JPA 연관관계 매핑 5. 즉시 로딩과 지연 로딩 (0) | 2020.01.23 |
JPA 연관관계 매핑 4. 프록시 (0) | 2020.01.23 |