JPQL(Java Persistence Query Language)
JPQL์ SQL์ ์ถ์ํํ์ฌ ํน์ ๋ฐ์ดํฐ๋ฒ ์ด์ค SQL์ ์์กด์ ์ด์ง ์์ ๊ฐ์ฒด์งํฅ ์ฟผ๋ฆฌ ์ธ์ด์ ๋๋ค.
ํ ์ด๋ธ์ ๋์์ผ๋ก ์ฟผ๋ฆฌ๋ฅผ ํ๋๊ฒ์ด ์๋ ๊ฐ์ฒด(์ํฐํฐ)๋ฅผ ๋์์ผ๋ก ์ฟผ๋ฆฌ๋ฅผ ํ๊ธฐ์ ๊ฐ์ฒด์งํฅ ์ฟผ๋ฆฌ ์ธ์ด๋ผ๊ณ ๋ถ๋ฆฝ๋๋ค.
JPQL์ ๊ฒฐ๊ตญ SQL๋ก ๋ณํ๋์ด ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ์ ๋ฌ๋ฉ๋๋ค.
JPQL ๋ฌธ๋ฒ
์์
select m from Member as m where m.age > 18
- ์ํฐํฐ์ ์์ฑ์ ๋์๋ฌธ์๋ฅผ ๊ตฌ๋ถํฉ๋๋ค. (Member, age)
- JPQL ํค์๋๋ ๋์๋ฌธ์๋ฅผ ๊ตฌ๋ถํ์ง ์์ต๋๋ค. (SELECT, select ๋ชจ๋ ๊ฐ๋ฅ)
- ํ ์ด๋ธ์ด ์๋ ์ํฐํฐ์ ์ด๋ฆ์ ์ฌ์ฉํฉ๋๋ค. (Member)
- ๋ณ์นญ์ ํ์์ ๋๋ค. (m) (as๋ ์๋ต ๊ฐ๋ฅ)
EXISTS, IN, AND, OR, NOT, =, >, >=, <, <=, <>, BETWEEN, LIKE, IS NULL ๋ฑ์ ๋ฌธ๋ฒ์ ์ง์ํฉ๋๋ค.
IN
ํ์์ id(PK)๊ฐ 1,2,3์ธ ํ์์ ์ฐพ์๋ผ
select m from Member m where m.id in (1,2,3)
ํ๋ผ๋ฏธํฐ ๋ฐ์ธ๋ฉ
SELECT m FROM Member m where m.username = :username
query.setParameter("username", usernameParam);
= : ํ๋ผ๋ฏธํฐ ๋ณ์นญ ์ฌ์ด์๋ ๊ณต๋ฐฑ์ด ์์ด๋ ์๊ด์์ต๋๋ค.
์ฆ ๋ค์ ๋ชจ๋๊ฐ ๊ฐ๋ฅํฉ๋๋ค.
SELECT m FROM Member m where m.username=:username
SELECT m FROM Member m where m.username= :username
SELECT m FROM Member m where m.username =:username
SELECT m FROM Member m where m.username =: username
SELECT m FROM Member m where m.username = : username
๋ฐํ ํ์
TypedQuery
๋ฐํ ํ์ ์ด ๋ช ํํ ๋ ์ฌ์ฉํฉ๋๋ค.
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");
๊ฒฐ๊ณผ ์กฐํ
qeury.getResultList(): ๊ฒฐ๊ณผ๊ฐ ํ๋ ์ด์์ผ ๋, ๋ฆฌ์คํธ๋ฅผ ๋ฐํํฉ๋๋ค. (๊ฒฐ๊ณผ๊ฐ ์๋ค๋ฉด ๋น ๋ฆฌ์คํธ๋ฅผ ๋ฐํํฉ๋๋ค.)
query.getSingleResult() : ๊ฒฐ๊ณผ๊ฐ ์ ํํ ํ๋์ผ๋ ์ฌ์ฉํฉ๋๋ค. ๋จ์ผ ๊ฐ์ฒด๋ฅผ ๋ฐํํฉ๋๋ค.
(๊ฒฐ๊ณผ๊ฐ ์์ผ๋ฉด NoResultException, ๊ฒฐ๊ณผ๊ฐ ๋ ์ด์์ด๋ฉด NonUniqueResultException์ด ๋ฐ์ํฉ๋๋ค.)
ํ๋ก์ ์
ํ๋ก์ ์ ์ด๋ SELECT ์ ์์ ์กฐํํ ๋์์ ์ง์ ํ๋ ๊ฒ์ ๋๋ค.
JPQL์์ ํ๋ก์ ์ ์ ๋์์ ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
- ์ํฐํฐ
- ์๋ฒ ๋๋ ํ์
- ์ค์นผ๋ผ ํ์ (์ซ์, ๋ฌธ์ ๋ฑ ๊ธฐ๋ณธ ๋ฐ์ดํฐ ํ์ )
์์ ์ฝ๋๋ฅผ ์ํ ํด๋์ค๋ ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
@Entity
@Table(name = "member")
class Member(
@Id @Column(name = "member_id")
@GeneratedValue(strategy = GenerationType.IDENTITY)
var id: Long = 0,
var username: String,
var age: Int,
@Embedded
var address: Address,
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "team_id")
var team: Team? = null,
) {}
@Embeddable
class Address(
var city: String,
var street: String,
var zipCode: String,
) {}
@Entity
@Table(name = "team")
class Team(
@Id @Column(name = "team_id")
@GeneratedValue(strategy = GenerationType.IDENTITY)
var id: Long = 0,
var name: String,
@OneToMany(mappedBy = "team")
var members: MutableList<Member> = ArrayList()
) {}
์ํฐํฐ ํ๋ก์ ์
SELECT m FROM Member m
SELECT m.team FROM Member m
inner join์ด ๋ฐ์ํฉ๋๋ค.
์ด๋ ๋ค์๊ณผ ๊ฐ์ด join์ด ๋ฐ์ํ๋ ๊ฒ์ ๋ช ํํ๊ฒ ์์ฑํ๋ ๊ฒ์ ์ถ์ฒํฉ๋๋ค
SELECT t FROM Member m join m.team t
์๋ฒ ๋๋ ํ์
SELECT m.address FROM Member m
์ค์นผ๋ผ ํ์
SELECT m.username, m.age FROM Member m
์ค์นผ๋ผ ํ์ ํ๋ก์ ์ ์ ๊ฒฐ๊ณผ ์กฐํ ๋ฐฉ๋ฒ
- Query ํ์ ์ผ๋ก ์กฐํ
- Object[] ํ์ ์ผ๋ก ์กฐํ (List<Object[]>)
- new ๋ช
๋ น์ด๋ก ์กฐํ (๋จ์ ๊ฐ์ DTO๋ก ๋ฐ๋ก ์กฐํํ๋ ๋ฐฉ๋ฒ์
๋๋ค.
- SELECT new jpabook.dto.UserDTO(m.name, m.age) FROM Member m
- DTO ํด๋์ค์๋ ํจํค์ง ๋ช ์ ํฌํจํ ์ ์ฒด ํด๋์ค ๋ช ์ ์ ๋ ฅํด์ผ ํฉ๋๋ค.
- ์์์ ํ์ ์ด ์ผ์นํ๋ ์์ฑ์๊ฐ ํ์ํฉ๋๋ค.
DISTINCT๋ก ์ค๋ณต์ ์ ๊ฑฐํ ์ ์์ต๋๋ค.
ํ์ด์ง
JPA๋ ํ์ด์ง์ ๋ค์ ๋๊ฐ์ API๋ก ์ถ์ํ ํ์์ต๋๋ค.
setFirstResult(int startPosition) : ์กฐํ ์์ ์์น (0๋ถํฐ ์์)
setMaxResults(int maxResult) : ์กฐํํ ๋ฐ์ดํฐ ์
์์
for (i in 1 .. 100) {
em.persist(Member(username = "username${i}", age = i, address = Address("c", "s", "z") ))
}
em.flush()
em.clear()
val createQuery = em.createQuery("select m from Member m", Member::class.java)
println("setFirstResult(0).setMaxResults(10)")
createQuery.setFirstResult(0).setMaxResults(10).resultList.forEach {
println("Member [${it.username}], age = ${it.age}")
}
println("setFirstResult(1).setMaxResults(10)")
createQuery.setFirstResult(1).setMaxResults(10).resultList.forEach {
println("Member [${it.username}], age = ${it.age}")
}
println("setFirstResult(2).setMaxResults(10)")
createQuery.setFirstResult(2).setMaxResults(10).resultList.forEach {
println("Member [${it.username}], age = ${it.age}")
}
๋ค์ ์ฝ๋์ ๊ฒฐ๊ณผ๋ ์๋์ ๊ฐ์ต๋๋ค.
์กฐ์ธ
๋ด๋ถ ์กฐ์ธ
SELECT m FROM Member m (inner) join m.team t //(๋ด๋ถ ์กฐ์ธ์ ๊ฒฝ์ฐ inner ์๋ต ๊ฐ๋ฅ)
์ธ๋ถ ์กฐ์ธ
SELECT m FROM Member m left (outer) join m.team t //(์ธ๋ถ ์กฐ์ธ์ ๊ฒฝ์ฐ left๋ ํ์, outer๋ ์๋ต ๊ฐ๋ฅ)
๋ ๊ฒฐ๊ณผ๋ ์์ ํ ๋์ผํฉ๋๋ค.
์ปฌ๋ ์ ์กฐ์ธ
SELECT t FROM Team t left join t.members m
์ธํ ์กฐ์ธ
SELECT m FROM Member m, Team t wherem.username = t.name
์ธํ ์กฐ์ธ์ Cross Join์ด ๋ฐ์ํฉ๋๋ค (์นดํ ์์ ๊ณฑ)
๋ํ ๊ธฐ๋ณธ์ ์ผ๋ก๋ ๋ด๋ถ ์กฐ์ธ๋ง ๊ฐ๋ฅํ๋ฉฐ, ON์ ์ฐ๋ฉด ์ธ๋ถ ์กฐ์ธ๋ ๊ฐ๋ฅํด์ง๋๋ค.
JOIN ON ์
๋ด๋ถ ์กฐ์ธ์ on์ ์ WHERE ์ ๊ณผ ๊ฒฐ๊ณผ๊ฐ ๋๊ฐ์ผ๋ฏ๋ก ๋ณดํต JOIN ON์ ์ ์ธ๋ถ ์กฐ์ธ์์๋ง ์ฌ์ฉํฉ๋๋ค
- ์กฐ์ธ ๋์ ํํฐ๋ง
- ์ฐ๊ด๊ด๊ณ ์๋ ์ํฐํฐ ์ธ๋ถ ์กฐ์ธ ๊ฐ๋ฅ(ํ์ด๋ฒ๋ค์ดํธ 5.1๋ถํฐ ์ง์)
ํ์๊ณผ ํ์ ์กฐ์ธํ๋๋ฐ, ํ ์ด๋ฆ์ด A์ธ ํ๋ง ์กฐ์ธ
SELECT m, t FROM Member m LEFT JOIN m.team t on t.name = 'A'
ํ์์ ์ด๋ฆ๊ณผ ํ์ ์ด๋ฆ์ด ๊ฐ์ ๋์ ์ธ๋ถ ์กฐ์ธ(์ฐ๊ด๊ด๊ณ ์๋ ์ํฐํฐ ์ธ๋ถ ์กฐ์ธ)
SELECT m, t FROM Meber m LEFT JOIN Team t on m.usernam = t.name
์๋ธ ์ฟผ๋ฆฌ
JPQL๋ SQL์ฒ๋ผ ์๋ธ ์ฟผ๋ฆฌ๋ฅผ ์ง์ํฉ๋๋ค.
๊ทธ๋ฌ๋ ๋ช ๊ฐ์ง ์ ์ฝ์ด ์๋๋ฐ, ์๋ธ์ฟผ๋ฆฌ๋ฅผ WHERE, HAVING ์ ์์๋ง ์ฌ์ฉํ ์ ์๊ณ SELECT, FROM ์ ์์๋ ์ฌ์ฉํ ์ ์์ต๋๋ค.
(๊ทธ๋ฌ๋ ํ์ด๋ฒ๋ค์ดํธ์์๋ SELECT์ ์ ์๋ธ ์ฟผ๋ฆฌ๋ ํ์ฉํฉ๋๋ค.)
๋์ด๊ฐ ํ๊ท ๋ณด๋ค ๋ง์ ํ์ ์ฐพ๊ธฐ
select m from Member m where m.age > (select avg(m2.age) from Member m2)
ํ ๊ฑด์ด๋ผ๋ ์ฃผ๋ฌธํ ๊ณ ๊ฐ
select m from Member m where (select count(o) from Order o where m = o.member) > 0
์๋ธ ์ฟผ๋ฆฌ ํจ์
- [NOT] EXISTS (์๋ธ์ฟผ๋ฆฌ) : ์๋ธ์ฟผ๋ฆฌ์ ๊ฒฐ๊ณผ๊ฐ ์กด์ฌํ๋ฉด(์กด์ฌํ์ง ์์ผ๋ฉด) ์ฐธ
- ALL (์๋ธ์ฟผ๋ฆฌ): ๊ฒฐ๊ณผ๊ฐ ๋ชจ๋ ๋ง์กฑํ๋ฉด ์ฐธ
- ANY (์๋ธ์ฟผ๋ฆฌ): ์กฐ๊ฑด์ ํ๋๋ผ๋ ๋ง์กฑํ๋ฉด ์ฐธ
- SOME (์๋ธ์ฟผ๋ฆฌ): ANY์ ๋์ผ
- [NOT] IN (์๋ธ์ฟผ๋ฆฌ) : ์๋ธ์ฟผ๋ฆฌ์ ๊ฒฐ๊ณผ ์ค ํ๋๋ผ๋ ๊ฐ์ ๊ฒ์ด ์์ผ๋ฉด(์์ผ๋ฉด) ์ฐธ
EXIST
์๋ธ์ฟผ๋ฆฌ์ ๊ฒฐ๊ณผ๊ฐ ์กด์ฌํ๋ฉด ์ฐธ์ ๋๋ค.
NOT์ ๋ฐ๋๋ก ์๋ํฉ๋๋ค.
ํ A ์์์ธ ํ์
select m from Member m where exists (select t from m.team t where t.name = 'ํA')
ALL | ANY | SOME
๋น๊ต ์ฐ์ฐ์์ ๊ฐ์ด ์ฌ์ฉํ๋ฉฐ, ALL์ ์กฐ๊ฑด์ ๋ชจ๋ ๋ง์กฑํ๋ฉด ์ฐธ, ANY ํน์ SOME์ ์กฐ๊ฑด์ ํ๋๋ผ๋ ๋ง์กฑํ๋ฉด ์ฐธ์ ๋๋ค.
์ ์ฒด ์ํ ๊ฐ๊ฐ์ ์ ๊ณ ๋ณด๋ค ์ฃผ๋ฌธ๋์ด ๋ง์ ์ฃผ๋ฌธ๋ค
select o from Order o
where o.orderAmount > ALL (select p.stockAmount from Product p)
์ด๋ค ํ์ด๋ ํ์ ์์๋ ํ์
select m from Member m where m.team = ANY (select t from Team t)
์กฐ๊ฑด์ - CASE ์
๊ธฐ๋ณธ CASE ์
select
case when m.age <= 10 then 'ํ์'
when m.age >= 60 then '์ด๋ฅด์ '
end
from Member m
๋จ์ CASE ์
select
case t.name
when 'A' then 'ํA์ ๋๋ค'
when 'B' then 'ํB์ ๋๋ค'
else '๋๋จธ์ง ํ์ ๋๋ค'
end
from Team t
COALESCE : ํ๋์ฉ ์กฐํํด์ null์ด ์๋๋ฉด ๋ฐํ
์ฌ์ฉ์ ์ด๋ฆ์ด ์์ผ๋ฉด ์ด๋ฆ ์๋ ํ์์ ๋ฐํ
select coalesce(m.username, '์ด๋ฆ ์๋ ํ์') from Member m
NULLIF : ๋ ๊ฐ์ด ๊ฐ์ผ๋ฉด NULL, ๋ค๋ฅด๋ฉด ์ฒซ ๋ฒ์งธ ๊ฐ ๋ฐํ
์ฌ์ฉ์ ์ด๋ฆ์ด '๊ด๋ฆฌ์'๋ฉด null ๋ฐํ, ๋๋จธ์ง๋ ์๊ธฐ ์์ ์ ์ด๋ฆ ๋ฐํ
select NULLIF(m.username, '๊ด๋ฆฌ์') from Member m
JPQL ๊ธฐ๋ณธ ํจ์
- CONCAT
- SUBSTRING
- TRIM
- LOWER, UPPER
- LENGTH
- LOCATE
- ABS, SQRT, MOD
- SIZE, INDEX
ํน์ DB์์ ์ ๊ณตํ๋ ํจ์๋ฅผ ์ฌ์ฉํ๊ณ ์ถ๋ค๋ฉด ์๋ ๋ฐฉ๋ฒ์ ์ฌ์ฉํ ์ ์์ต๋๋ค.
์ฌ์ฉ์ ์ ์ ํจ์
์ฌ์ฉํ๋ DB ๋ฐฉ์ธ์ ์์๋ฐ๊ณ , ์ฌ์ฉ์ ์ ์ ํจ์๋ฅผ ๋ฑ๋กํฉ๋๋ค.
์ฌ์ฉ์ ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
select function('group_concat', i.name) from Item i
์ด๋ฏธ ํ์ด๋ฒ๋ค์ดํธ์์๋ ์ฌ์ฉ์ ์ ์ ํจ์๋ฅผ ๋ฑ๋กํด๋์์ต๋๋ค.
(DB ์ข ์์ ์ผ๋ก ๋์ํฉ๋๋ค.)
JPQL ์งํฉ๊ณผ ์ ๋ ฌ ๋ฑ
select
COUNT(m), //์ ์ฒด ์
SUM(m.age), //๋์ด์ ํฉ
AVG(m.age), // ๋์ด์ ํ๊ท
MAX(m.age),// ๋์ด์ ์ต๋๊ฐ
MIN(m.age) // ๋์ด์ ์ต์๊ฐ
from Member m
GROUP BY, HAVING, ORDER BY ๋ชจ๋ ๊ฐ๋ฅํฉ๋๋ค.
๊ฒฝ๋ก ํํ์
.(์ )์ ์ฐ์ด ๊ฐ์ฒด ๊ทธ๋ํ๋ฅผ ํ์ํ๋ ๊ฒ์ ์๋ฏธํฉ๋๋ค.
ํ์ํ ์ ์๋ ๋์์ ๋ค์๊ณผ ๊ฐ์ต๋๋ค
- ์ํ ๊ฐ ํ๋ ๊ฒฝ๋ก(m.age) : ๊ฒฝ๋ก ํ์์ ๋์ ๋๋ค. ๋๋ ํ์ํ ์ ์์ต๋๋ค.
- ๋จ์ผ ๊ฐ ์ฐ๊ด ๊ฒฝ๋ก(m.team) : ๋ฌต์์ ์ผ๋ก ๋ด๋ถ ์กฐ์ธ์ด ์ผ์ด๋ฉ๋๋ค. ๊ณ์ ํ์ํ ์ ์์ต๋๋ค.
- ์ปฌ๋ ์
๊ฐ ์ฐ๊ด ๊ฒฝ๋ก(m.orders o) : ๋ฌต์์ ์ผ๋ก ๋ด๋ถ ์กฐ์ธ์ด ์ผ์ด๋ฉ๋๋ค. ๋๋ ํ์ํ ์ ์์ต๋๋ค.
- ๋จ FROM ์ ์์ join์ ํตํด ๋ณ์นญ์ ์ป์ผ๋ฉด ๋ณ์นญ์ผ๋ก ํ์์ ์ํํ ์ ์์ต๋๋ค. (t.memebers m)
๋ฌต์์ ์กฐ์ธ์ ์ฌ์ฉํ์ง ๋ง๊ณ ๋ช ์์ ์กฐ์ธ์ ์ฌ์ฉํ๋ ๊ฒ์ ๊ถ์ฅํฉ๋๋ค. (๋ช ์์ ์ผ๋ก JOIN ํค์๋๋ฅผ ์ฌ์ฉ)
๋คํ์ฑ ์ฟผ๋ฆฌ
JPQL๋ก ๋ถ๋ชจ ์ํฐํฐ๋ฅผ ์กฐํํ๋ฉด ๊ทธ ์์ ์ํฐํฐ๋ ํจ๊ป ์กฐํ๋ฉ๋๋ค.
๋คํ์ฑ ์ฟผ๋ฆฌ๋ ์กฐํ ๋์์ ํน์ ์์์ผ๋ก ํ์ ํ๊ธฐ ์ํด ์ฌ์ฉํ๋ ๋ฐฉ๋ฒ์ ๋๋ค.
TYPE
Item ์ค์ Book, Movie๋ฅผ ์กฐํํ๋ผ.
select i from Item i where type(i) IN (Book, Movie)
TREAT
์๋ฐ์ ํ์ ์บ์คํ ๊ณผ ๋น์ทํฉ๋๋ค.
์์ ๊ตฌ์กฐ์์ ๋ถ๋ชจ๋ฅผ ํน์ ์์์ ํ์ ์ผ๋ก ๋ค๋ฃฐ ๋ ์ฌ์ฉํฉ๋๋ค
select i form Item i where treat (i as Book).author = 'kim'
Reference
[์๋ฐ ORM ํ์ค JPA ํ๋ก๊ทธ๋๋ฐ - ๊น์ํ]
'๐๏ธ Spring > JPA' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
[JPA] JPQL์ ๋ฒํฌ ์ฐ์ฐ (0) | 2021.12.17 |
---|---|
[JPA] JPQL Named ์ฟผ๋ฆฌ (0) | 2021.12.17 |
[JPA] JPA์ ๋ค์ํ ์ฟผ๋ฆฌ ๋ฐฉ๋ฒ (JPQL, JdbcTemplate) (0) | 2021.12.16 |
[JPA] @AttributeOverride - ๋งคํ ์ ๋ณด ์ฌ์ ์ (1) | 2021.12.16 |
[JPA] ์์์ฑ ์ ์ด(CASCADE)์ ๊ณ ์ ๊ฐ์ฒด (0) | 2021.12.15 |