"인프런 - 자바 ORM 표준 JPA 프로그래밍 강의를 듣고 작성한 글 입니다."
www.inflearn.com/course/ORM-JPA-Basic#
자바 ORM 표준 JPA 프로그래밍 - 기본편 - 인프런
JPA를 처음 접하거나, 실무에서 JPA를 사용하지만 기본 이론이 부족하신 분들이 JPA의 기본 이론을 탄탄하게 학습해서 초보자도 실무에서 자신있게 JPA를 사용할 수 있습니다. 초급 웹 개발 프로그
www.inflearn.com
JPQL(Java Persistence Query Language)
- JPQL 은 객체지향 쿼리 언어이다, 따라서 테이블을 대상으로 쿼리를 하는 것이 아닌 Entity 객체를 대상으로 쿼리 한다.
- JPQL 은 SQL 을 추상화해서 특정 데이터베이스 SQL 에 의존하지 않는다.
- JPQL 은 결국 SQL 로 변환된다.
* JPQL 의 기본 문법은 일반 SQL 문과 거의 똑같다.
JPA 에서 값을 바꿀때는 update 같은 것 없이 값만 변경되면, 트랜잭션 커밋 시점에 지동으로 update query 가 DB 에 전달된다.
그런데 이건 한건, 한건 씩 변경 사항을 적용할 때의 얘기이다.
그렇다면 한번에 여러가지의 데이터를 변경해야 하는 경우는 어떨까?
* 벌크 연산 : 한번에 여러가지의 데이터를 함께 처리하는 기능
update_문 :: update_절 [where_절]
delete_문 :: delete_절 [where_절]
-> JPA 에서 따로 관리하는 기능으로 추후에 다루게 될 때 자세하게 알아보자.
JPQL 문법
JPQL 문법 예시 : select m from Member as m where m.age > 18
- Entity 와 속성은 대,소문자를 구분한다.(Member, age) -> 자바 클래스에서 대,소문자를 구분하듯이 JPQL 에서도 객체에 대한 대,소문자를 구분한다.
- JPQL 키워드는 대,소문자를 구분하지 않는다.(SELECT FROM, where)
- 테이블 이름이 아닌, Entity 이름을 사용하며(Member) 별칭은 필수이다.(m, as 는 생략 가능)
* 집합과 정렬
기존 SQL 과 같이 select COUNT(), SUM(), AVG() 와 같은 집합이나 정렬 기능이 다 제공된다.
-> GROUP BY, HAVING, ORDER BY 또한 마찬가지로 똑같이 사용하면 된다.
TypedQuery, Query
- TypedQuery : 반환 타입이 명확할 때 사용한다.
- Query : 반환 타입이 명확하지 않을 때 사용한다.
- JpaMain.java
// 타입 정보를 명기할 수 있는 경우
TypedQuery<Member> query1 = em.createQuery("select m from Member m", Member.class);
TypedQuery<String> query2 = em.createQuery("select m.username from Member m", String.class);
// 타입 정보를 명기할 수 없는 경우
Query query3 = em.createQuery("select m.username, m.age from Member m");
// 찾아오는 데이터의 타입이 복수 일 경우 Member.class 와 같이 타입을 명기할 수가 없게된다.
* 결과 조회
- 결과가 하나 이상일 때, 즉 반환값이 컬렉션 타입일 경우 리스트를 반환한다. 결과가 없으면 빈 리스트를 반환한다.(즉, NullPointerException 에 대한 걱정을 하지 않아도 된다.)
-> query.getResultList();
- 결과가 정확히 하나 일 경우 단일 객체를 반환한다.(진짜 결과가 하나만 나올때만 써야 한다, 조심해야 함)
-> query.getSingleResult();
-> 단일 객체를 반환할 때 결과가 없을 경우 발생하는 익셉션 : NoResultException
-> 단일 객체를 반환할 때 결과가 둘 이상일 경우 발생하는 익셉션 : NonUniqueResultException
- JpaMain.java
List<Member> resultList = query1.getResultList(); // 결과가 하나 이상일 경우 List 타입으로 반환
Member result = query1.getSingleResult();
// 결과가 하나 일 경우 사용하는 메소드(식별자를 잘 활용해야 한다.)
* 그런데 결과가 둘 이상일 경우엔 익셉션이 터지는 걸 당연하게 볼 수 있으나, 결과가 없을 경우에 익셉션이 터지는 것에 대해서는 논란이 있다고 한다.(괜히 try - catch 문을 사용해야 하므로....)
그래서 나중에 Spring Data JPA 를 사용하게 되면 하나만 가져오는 함수들을 추상화 시켜서 제공을 해주는데, 이 경우 결과가 없으면 그냥 null 을 반환하거나 optional 을 반환한다.
즉, 익셉션을 터트리지 않는다.
그런데 이것도 결국 Spring 에서 코드 내부 구조를 살펴보면 try - catch 문을 사용하고 있는 것을 볼 수 있다.
(Spring Data JPA 쓸 때랑 헷갈리지 말자!)
파라미터 바인딩(Parameter Binding)
이름, 위치를 기준으로 파라미터를 바인딩 해줄 수 있다.
- JpaMain.java
Member member = new Member();
member.setUsername("member1");
member.setAge(10);
em.persist(member);
TypedQuery<Member> query4 = em.createQuery("select m from Member m where m.username = :username", Member.class);
query4.setParameter("username", "member1"); // where 절 parameter binding
Member singleResult = query4.getSingleResult();
System.out.println("singleResult = " + singleResult.getUsername());
- Hibernate SQL
Hibernate:
/* select
m
from
Member m
where
m.username = :username */ select
member0_.id as id1_0_,
member0_.age as age2_0_,
member0_.TEAM_ID as team_id4_0_,
member0_.username as username3_0_
from
Member member0_
where
member0_.username=?
singleResult = member1
위의 코드를 파라미터 체인을 활용하여 작성하면 다음과 같이 할 수 있다.
- JpaMain.java
Member param_result = em.createQuery("select m from Member m where m.username = :username", Member.class)
.setParameter("username", "member1")
.getSingleResult();
System.out.println("param_result = " + param_result.getUsername());
- Hibernate SQL
Hibernate:
/* select
m
from
Member m
where
m.username = :username */ select
member0_.id as id1_0_,
member0_.age as age2_0_,
member0_.TEAM_ID as team_id4_0_,
member0_.username as username3_0_
from
Member member0_
where
member0_.username=?
param_result = member1
파라미터 바인딩을 할 때 주의할 점?
- 위치 기준 바인딩은 왠만하면 쓰지 말자.
: 1,2,3 순서상에서 중간에 다른 데이터를 하나 더 끼워넣으면 순서가 밀려버려서 장애가 발생하게 될 수도 있다.
반면에 이름 기준 바인딩을 활용하면 위치가 바뀐다고 해도 그로인한 장애가 발생하지 않게 된다.
다음 글에서는 JPQL 에서의 프로젝션, 페이징과 같은 다른 기능들 또한 알아보자.
'JPA' 카테고리의 다른 글
JPQL - JPQL 기본(3) (0) | 2020.11.16 |
---|---|
JPQL - JPQL 기본(2) (0) | 2020.11.15 |
JPQL - JPQL 소개(2) (0) | 2020.11.13 |
JPQL - JPQL 소개(1) (0) | 2020.11.13 |
실전 예제 6 - 값 타입 (0) | 2020.10.22 |