반응형
JPA 게시글은 대부분 인프런의 김영한님의 강의인 '자바 ORM 표준 JPA 프로그래밍' 기반으로 내용을 정리했습니다.
기본 문법과 쿼리 API
- JPQL? Java Persistence Query Language
JPQL
- JPQL은 객체지향 쿼리 언어. 따라서 테이블이 아닌 엔티티 객체를 대상으로 쿼리한다.
- JPQL은 SQL을 추상화해서 특정 데이터베이스 SQL에 의존하지 않는다. → 방언
- JPQL은 결국 SQL로 변환이 된다. (매핑 정보 + 방언 = SQL)
프로젝트 새로 생성 후
Member.class
@Entity
public class Member {
@Id @GeneratedValue
private Long id;
private String username;
private int age;
@ManyToOne
@JoinColumn(name = "TEAM_ID")
private Team team;
// getter/setter 생략
}
Team.class
@Entity
public class Team {
@Id @GeneratedValue
private Long id;
private String name;
@OneToMany(mappedBy = "team")
private List<Member> members = new ArrayList<>();
// getter/setter 생략
}
Address.class
@Embeddable
public class Address {
private String city;
private String street;
private String zipcode;
// getter/setter 생략
}
Order.class
@Entity
@Table(name = "ORDERS")
public class Order {
@Id @GeneratedValue
private Long id;
private int orderAmount;
@Embedded
private Address address;
@ManyToOne
@JoinColumn(name="PRODUCT_ID")
private Product product;
// getteer/setter 생략
}
Product.class
@Entity
public class Product {
@Id @GeneratedValue
private Long id;
private String name;
private int price;
private int stockAmount;
// getter/setter 생략
}
JPQL 문법
- 전체적으로 SQL과 유사하다.
select m from Member as m where m.age > 18
- 엔티티와 속성은 대소문자를 구분한다.
- JPQL 키워드(SELECT, FROM, where)는 대소문자를 구분하지 않는다.
- 엔티티 이름 사용한다. MEMBER 테이블이 아니고 Member 엔티티 이름이다.
- 별칭(m)은 필수이다. (as는 생략 가능함)
집합과 정렬
select
COUNT(m), // 회원수
SUM(m.age), // 나이, 합
AVG(m.age), // 나이, 평균
MAX(m.age), // 최대 나이
MIN(m.age) // 최소 나이
from Member m
- GROUP BY, HAVING
- ORDER BY
다 사용이 가능하다.
TypeQuery, Query
- TypeQuery : 반환 타입이 명확할 때 사용한다.
TypedQuery<Member> query =
em.createQuery("SELECT m FROM Member m", Member.class);
- Query : 반환 타입이 명확하지 않을 때 사용한다.
Query query =
em.createQuery("SELECT m.username, m.age from Member m");
- Query의 경우 m.username 만 가져왔을 때는 반환 타입을 String.class로 해줘도 되는데 위의 예제 코드에서는 m.age까지 가져오므로 타입을 특정할 수가 없기 때문에 Query를 사용한다.
결과 조회 API
- query.getResultList() : 조회 결과가 하나 이상일 때 리스트로 반환해준다.
- 결과가 없을 경우엔 빈 리스트를 반환한다.
TypedQuery<Member> query =
em.createQuery("select m from Member m", Member.class);
List<Member> resultList = query.getResultList();
for (Member member1 : resultList) {
System.out.println("member1 = " + member1);
}
- query.getSingleResult() : 결과가 정확히 하나일 때 단일 객체로 반환해준다.
- 결과가 없을 경우 : javax.persistence.NoResultException
- 둘 이상이면 : javax.persistence.NonUniqueResultException
TypedQuery<Member> query =
em.createQuery("select m from Member m", Member.class);
Member result = query.getSingleResult();
System.out.println("result = " + result);
- 결과가 없을 경우엔 getResultList()처럼 null을 반환해주면 될 거 같은데 굳이 예외를 터트려준다. 그래서 결과가 없는 경우엔 따로 try~catch를 작성해줘야한다.
- Spring Data JPA는 null이나 Optional로 반환해준다.
파라미터 바인딩 - 이름 기준, 위치 기준
- 위치 기준은 쿼리는 위치에 따라 쿼리가 이상하게 작동될 수 있는 위험이 있어 사용하지 않는 것이 좋다.
- 이름 기준으로 사용하자.
TypedQuery<Member> query =
em.createQuery("select m from Member m where m.username = :username", Member.class);
query.setParameter("username", "member1");
Member singleResult = query.getSingleResult();
System.out.println("singleResult = " + singleResult.getUsername());
이렇게 사용할 수도 있고 메서드 체이닝으로 사용할 수도 있다. 추천하는 방법은 메서드 체이닝 방법이다.
Member result = em.createQuery("select m from Member m where m.username = :username", Member.class)
.setParameter("username", "member1")
.getSingleResult();
System.out.println("result = " + result.getUsername());
반응형