Post

[JPA] JPQL

[JPA] JPQL

๐Ÿ“Œ JPQL์ด๋ž€?

JPQL(Java Persistence Query Language) ๋Š” JPA์—์„œ ์‚ฌ์šฉํ•˜๋Š” ๊ฐ์ฒด ์ง€ํ–ฅ ์ฟผ๋ฆฌ ์–ธ์–ด์ด๋‹ค. SQL์„ ์ถ”์ƒํ™”ํ•œ ์ฟผ๋ฆฌ ์–ธ์–ด์ด๋ฉฐ, SQL๊ณผ ๋น„์Šทํ•œ ๋ฌธ๋ฒ•์„ ๊ฐ€์ง€์ง€๋งŒ SQL์€ ํ…Œ์ด๋ธ”์„ ๋Œ€์ƒ์œผ๋กœ ์ฟผ๋ฆฌ๋ฅผ ์ž‘์„ฑํ•˜๋Š” ๋ฐ˜๋ฉด JPQL์€ ์—”ํ‹ฐํ‹ฐ๋ฅผ ๋Œ€์ƒ์œผ๋กœ ์ฟผ๋ฆฌ๋ฅผ ์ž‘์„ฑํ•œ๋‹ค.

JPA์—์„œ ์ œ๊ณตํ•˜๋Š” ๊ธฐ๋ณธ ๋ฉ”์„œ๋“œ๋กœ ๋ณต์žกํ•œ ์กฐ๊ฑด์„ ๊ฐ€์ง„ ๋ฐ์ดํ„ฐ๋ฅผ ์กฐํšŒํ•˜๊ธฐ์—” ํ•œ๊ณ„๊ฐ€ ์žˆ์œผ๋ฉฐ, ์ด๋ฅผ ๊ทน๋ณตํ•˜๊ธฐ ์œ„ํ•ด JPQL์ด ๊ฐœ๋ฐœ๋˜์—ˆ๋‹ค. JPQL์€ ์ดํ›„ SQL๋กœ ๋ณ€ํ™˜๋œ๋‹ค.

๐Ÿ“Œ ๋ฌธ๋ฒ•

1
SELECT m FROMMember m WHERE m.age > 18
  • ์—”ํ‹ฐํ‹ฐ์™€ ์†์„ฑ์€ ๋Œ€์†Œ๋ฌธ์ž๋ฅผ ๊ตฌ๋ถ„ํ•œ๋‹ค. ๋‹จ, SELECT, WHERE๊ณผ ๊ฐ™์€ JPQL ํ‚ค์›Œ๋“œ๋Š” ๋Œ€์†Œ๋ฌธ์ž๋ฅผ ๊ตฌ๋ถ„ํ•˜์ง€ ์•Š๋Š”๋‹ค.
  • ํ…Œ์ด๋ธ” ์ด๋ฆ„์ด ์•„๋‹Œ ์—”ํ‹ฐํ‹ฐ ์ด๋ฆ„์„ ์‚ฌ์šฉํ•œ๋‹ค. ์—”ํ‹ฐํ‹ฐ ์ด๋ฆ„์€ @Entity ์–ด๋…ธํ…Œ์ด์…˜์œผ๋กœ ์„ค์ •ํ•  ์ˆ˜ ์žˆ๋‹ค.
  • ๋ณ„์นญ์„ ํ•„์ˆ˜๋กœ ์‚ฌ์šฉํ•ด์•ผ ํ•˜๋ฉฐ, AS๋Š” ์ƒ๋žต ๊ฐ€๋Šฅํ•˜๋‹ค.

๐Ÿ“Œ TypedQuery vs. Query

TypedQuery ์™€ Query ๋Š” JPQL์„ ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•œ ์ฟผ๋ฆฌ ํƒ€์ž…์ด๋‹ค. ๋‘ ํƒ€์ž… ๋ชจ๋‘ EntityManager ์˜ createQuery() ๋ฅผ ํ˜ธ์ถœํ•˜์—ฌ ์ƒ์„ฑํ•œ๋‹ค.

TypedQuery

TypedQuery๋Š” ์ฟผ๋ฆฌ ๊ฒฐ๊ณผ์˜ ๋ฆฌํ„ด ํƒ€์ž…์ด ๋ช…ํ™•ํ•  ๋•Œ ์‚ฌ์šฉํ•œ๋‹ค. ๋‘ ๋ฒˆ์งธ ์ธ์ž๋กœ ์—”ํ‹ฐํ‹ฐ ํด๋ž˜์Šค๋ฅผ ์ „๋‹ฌํ•œ๋‹ค.

1
2
TypedQuery<Member> typedQuery = em.createQuery("select m from Member m where m.age > 18", Member.class);
List<Member> members = typedQuery.getResultList();

getResultList()๋Š” ๊ฒฐ๊ณผ๊ฐ€ ํ•˜๋‚˜ ์ด์ƒ์ผ ๋•Œ ์‚ฌ์šฉํ•˜๋ฉฐ ๊ฒฐ๊ณผ๊ฐ€ ๋ฆฌ์ŠคํŠธ ํƒ€์ž…์ด๋‹ค. getSingleResult() ๋Š” ๊ฒฐ๊ณผ๊ฐ€ ํ•˜๋‚˜์ผ ๋•Œ ์‚ฌ์šฉํ•˜๋ฉฐ ๋‹จ์ผ ๊ฐ์ฒด๋ฅผ ๋ฆฌํ„ดํ•œ๋‹ค.

TypedQuery๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ๋ฆฌํ„ด๋˜๋Š” ๊ฒฐ๊ณผ๋ฅผ ๋ณ„๋„์˜ ์บ์ŠคํŒ… ์—†์ด ๋ฐ”๋กœ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค. ๋˜ํ•œ ํƒ€์ž… ์•ˆ์ „์„ฑ์„ ๋ณด์žฅํ•˜๋ฏ€๋กœ ์ปดํŒŒ์ผ ์‹œ์ ์— ํƒ€์ž… ์˜ค๋ฅ˜๋ฅผ ์žก์„ ์ˆ˜ ์žˆ๋‹ค.

Query

Query๋Š” ๋ฆฌํ„ด ํƒ€์ž…์ด ๋ช…ํ™•ํ•˜์ง€ ์•Š๊ฑฐ๋‚˜ ์—ฌ๋Ÿฌ ์ปฌ๋Ÿผ์„ ์„ ํƒํ•˜์—ฌ ์กฐํšŒํ•  ๋•Œ ์‚ฌ์šฉํ•œ๋‹ค.

1
2
Query query = em.createQuery("select m.username, m.age from Member m where m.age > 18");
List<Object[]> resultList = query.getResultList();

Query ํƒ€์ž…์˜ ๊ฒฐ๊ณผ๋ฅผ ์‚ฌ์šฉํ•  ๋•Œ ์ ์ ˆํ•œ ํƒ€์ž…์œผ๋กœ ์บ์ŠคํŒ…ํ•˜์—ฌ ์‚ฌ์šฉํ•ด์•ผ ํ•œ๋‹ค.

๐Ÿ“Œ ํŒŒ๋ผ๋ฏธํ„ฐ ๋ฐ”์ธ๋”ฉ

ํŒŒ๋ผ๋ฏธํ„ฐ ๋ฐ”์ธ๋”ฉ์€ JPQL์—์„œ ์ฟผ๋ฆฌ์— ํŠน์ • ๊ฐ’์„ ๋™์ ์œผ๋กœ ์ „๋‹ฌํ•˜๋Š” ๋ฐฉ๋ฒ•์ด๋‹ค. ์ด๋ฅผ ํ†ตํ•ด SQL Injection์„ ๋ฐฉ์ง€ํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ ์ฟผ๋ฆฌ ์žฌ์‚ฌ์šฉ์„ฑ์„ ๋†’์ผ ์ˆ˜ ์žˆ๋‹ค.

์ด๋ฆ„ ๊ธฐ์ค€ ํŒŒ๋ผ๋ฏธํ„ฐ

ํŒŒ๋ผ๋ฏธํ„ฐ๋ฅผ ์ด๋ฆ„์„ ๊ตฌ๋ถ„ํ•˜๋Š” ๋ฐฉ์‹์ด๋‹ค. โ€˜:โ€™์„ ์‚ฌ์šฉํ•˜์—ฌ ํŒŒ๋ผ๋ฏธํ„ฐ ์ด๋ฆ„์„ ์ง€์ •ํ•œ๋‹ค.

1
2
3
TypedQuery<Member> query = em.createQuery("SELECT m FROM Member m WHERE m.username = :username", Member.class);
query.setParameter("username", "member1");
List<Member> resultList = query.getResultList();

์œ„์น˜ ๊ธฐ์ค€ ํŒŒ๋ผ๋ฏธํ„ฐ

โ€˜?โ€™ ๋’ค์— ์œ„์น˜ ๊ฐ’์„ ์ง€์ •ํ•˜๋Š” ๋ฐฉ์‹์ด๋‹ค. ์œ„์น˜ ๊ฐ’์€ 1๋ถ€ํ„ฐ ์‹œ์ž‘ํ•œ๋‹ค.

1
2
3
TypedQuery<Member> query = em.createQuery("SELECT m FROM Member m WHERE m.username = ?1", Member.class);
query.setParameter(1, "member1");
List<Member> resultList = query.getResultList();

์ผ๋ฐ˜์ ์œผ๋กœ ์œ„์น˜ ๊ธฐ์ค€ ํŒŒ๋ผ๋ฏธํ„ฐ ๋ฐ”์ธ๋”ฉ๋ณด๋‹ค ์ด๋ฆ„ ๊ธฐ์ค€ ํŒŒ๋ผ๋ฏธํ„ฐ ๋ฐ”์ธ๋”ฉ์ด ๋” ๊ถŒ์žฅ๋œ๋‹ค.

๋ฉ”์„œ๋“œ ์ฒด์ด๋‹

JPQL API๋Š” ๋ฉ”์„œ๋“œ ์ฒด์ธ ํ˜•์‹์œผ๋กœ ์„ค๊ณ„๋˜์–ด ์žˆ๋‹ค.

1
2
3
List<Member> members = em.createQuery("SELECT m FROM Member m WHERE m.username = :username", Member.class)
    .setParameter("username", "member1")
    .getResultList(); 

๐Ÿ“Œ ํ”„๋กœ์ ์…˜

ํ”„๋กœ์ ์…˜(Projection)์€ JPQL์—์„œ์˜ SELECT์ ˆ์— ์กฐํšŒํ•  ๋Œ€์ƒ์„ ์ง€์ •ํ•˜๋Š” ๊ฒƒ์„ ์˜๋ฏธํ•œ๋‹ค.

์—”ํ‹ฐํ‹ฐ ํ”„๋กœ์ ์…˜

์—”ํ‹ฐํ‹ฐ ์ž์ฒด๋ฅผ ์กฐํšŒ ๋Œ€์ƒ์„ ์ง€์ •ํ•˜๋Š” ๋ฐฉ์‹์ด๋‹ค.

1
2
SELECT m FROM Member m
SELECT m.team FROM Member m

์—”ํ‹ฐํ‹ฐ ํ”„๋กœ์ ์…˜์œผ๋กœ ์กฐํšŒ๋œ ๊ฒฐ๊ณผ๋Š” ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ์—์„œ ๊ด€๋ฆฌ๋œ๋‹ค.

์ž„๋ฒ ๋””๋“œ ํƒ€์ž… ํ”„๋กœ์ ์…˜

์—”ํ‹ฐํ‹ฐ์— ํฌํ•จ๋œ ์ž„๋ฒ ๋””๋“œ ํƒ€์ž…์„ ์กฐํšŒํ•˜๋Š” ๋ฐฉ์‹์ด๋‹ค.

1
2
3
4
SELECT m.address FROM Member m

-- ๋ถˆ๊ฐ€๋Šฅ
SELECT a FROM Address a

์ž„๋ฒ ๋””๋“œ ํƒ€์ž…์€ ์—”ํ‹ฐํ‹ฐ์™€ ์œ ์‚ฌํ•˜๊ฒŒ ์‚ฌ์šฉ๋˜์ง€๋งŒ, ์กฐํšŒ์˜ ์‹œ์ž‘์ ์ด ๋  ์ˆ˜ ์—†๋‹ค.

์Šค์นผ๋ผ ํƒ€์ž… ํ”„๋กœ์ ์…˜

์ˆซ์ž๋‚˜ ๋ฌธ์ž ๊ฐ™์€ ๊ธฐ๋ณธ ๋ฐ์ดํ„ฐ ํƒ€์ž…์„ ์กฐํšŒํ•˜๋Š” ๋ฐฉ์‹์ด๋‹ค.

1
SELECT m.username FROM Member m

์—ฌ๋Ÿฌ ์Šค์นผ๋ผ ๊ฐ’๋„ ํ•จ๊ป˜ ์กฐํšŒํ•  ์ˆ˜ ์žˆ๋‹ค. Object[] ํƒ€์ž…์œผ๋กœ ์กฐํšŒํ•˜๋Š” ๋ฐฉ๋ฒ•๊ณผ JPQL์˜ new ํ‚ค์›Œ๋“œ์™€ DTO ํด๋ž˜์Šค๋ฅผ ํ†ตํ•ด ์กฐํšŒํ•˜๋Š” ๋ฐฉ๋ฒ•์ด ์žˆ๋‹ค.

1
2
3
4
5
6
7
8
// Object[]
String jpql = "SELECT m.username, m.age FROM Member m";
List<Object[]> resultList = entityManager.createQuery(jpql).getResultList();

// DTO
String jpql = "SELECT new com.example.MemberDTO(m.username, m.age) FROM Member m";
List<MemberDTO> resultList = entityManager.createQuery(jpql, MemberDTO.class).getResultList();

DTO ํด๋ž˜์Šค๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•์ด ๋” ๊ถŒ์žฅ๋œ๋‹ค.

๐Ÿ“Œ ํŽ˜์ด์ง• API

JPQL์—์„œ ๋Œ€์šฉ๋Ÿ‰ ๋ฐ์ดํ„ฐ๋ฅผ ํšจ์œจ์ ์œผ๋กœ ์กฐํšŒํ•˜๊ธฐ ์œ„ํ•ด ํŽ˜์ด์ง•์„ ์‚ฌ์šฉํ•œ๋‹ค.

setFirstResult(int startPos) ๋Š” ์กฐํšŒ ์‹œ ์‹œ์ž‘ ์œ„์น˜๋ฅผ ์ง€์ •ํ•˜๋Š” ๋ฉ”์„œ๋“œ์ด๋‹ค. startPos + 1 ๋ฒˆ์งธ ๊ฒฐ๊ณผ๋ถ€ํ„ฐ ์กฐํšŒ๋ฅผ ์‹œ์ž‘ํ•œ๋‹ค. ์ธ๋ฑ์Šค๋Š” 0๋ถ€ํ„ฐ ์‹œ์ž‘ํ•œ๋‹ค.

setMaxResults(int maxResult) ๋Š” ํ•œ ๋ฒˆ์— ์กฐํšŒํ•  ๋ฐ์ดํ„ฐ์˜ ์ตœ๋Œ€ ๊ฐœ์ˆ˜๋ฅผ maxResult ๊ฐœ๋กœ ์ง€์ •ํ•˜๋Š” ๋ฉ”์„œ๋“œ์ด๋‹ค.

1
2
3
4
5
String jpql = "select m from Member m order by m.name desc";
List<Member> resultList = entityManager.createQuery(jpql, Member.class)
                              .setFirstResult(10)
                              .setMaxResults(20)
                              .getResultList();

์œ„ ์ฝ”๋“œ๋Š” 11๋ฒˆ ์งธ ๊ฒฐ๊ณผ๋ถ€ํ„ฐ 20๊ฐœ์˜ ๋ฐ์ดํ„ฐ๋ฅผ ์กฐํšŒํ•˜๋Š” ์ฝ”๋“œ์ด๋‹ค.

JPQL์˜ ํŽ˜์ด์ง• API๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด SQL์˜ ํŽ˜์ด์ง• ์ฟผ๋ฆฌ๋ฅผ ์ง์ ‘ ์ž‘์„ฑํ•  ํ•„์š”๊ฐ€ ์—†๋‹ค. ์—ฌ๋Ÿฌ DBMS๋งˆ๋‹ค ๋‹ค๋ฅธ ํŽ˜์ด์ง• ์ฒ˜๋ฆฌ ์ฟผ๋ฆฌ ๋ฌธ๋ฒ•์ด ์กด์žฌํ•˜๊ธฐ์—, ๊ฐœ๋ฐœ์ž๋Š” DBMS ์ข…๋ฅ˜์— ๊ตฌ์• ๋ฐ›์ง€ ์•Š๊ณ  ์ผ๊ด€๋œ ๋ฐฉ์‹์œผ๋กœ ํŽ˜์ด์ง• ๋กœ์ง์„ ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ๋‹ค.

๐Ÿ“Œ ์ง‘๊ณ„ ํ•จ์ˆ˜

JPQL์€ SQL๊ณผ ์œ ์‚ฌํ•œ ์ง‘๊ณ„ ํ•จ์ˆ˜๋ฅผ ์ œ๊ณตํ•œ๋‹ค.

COUNT(x): ๊ฒฐ๊ณผ์˜ ๊ฐœ์ˆ˜ ๋ฆฌํ„ด, Longํƒ€์ž…

SUM(x): ์ˆซ์ž ํ•„๋“œ์˜ ํ•ฉ๊ณ„ ๊ณ„์‚ฐ, Long , Double ํƒ€์ž…

AVG(x): ํ‰๊ท  ๊ณ„์‚ฐ, Double ํƒ€์ž…

MAX(x): ์ตœ๋Œ“๊ฐ’ ๊ณ„์‚ฐ

MIN(x): ์ตœ์†Ÿ๊ฐ’ ๊ณ„์‚ฐ

1
2
SELECT COUNT(m), SUM(m.age), AVG(m.age), MAX(m.age), MIN(m.age)
FROM Member m

๐Ÿ“Œ JOIN

Inner Join

๋‘ ์—”ํ‹ฐํ‹ฐ ๊ฐ„ ์—ฐ๊ด€๊ด€๊ณ„๊ฐ€ ์กด์žฌํ•˜๋Š” ๋ฐ์ดํ„ฐ๋งŒ ์กฐํšŒํ•œ๋‹ค. INNER ํ‚ค์›Œ๋“œ๋Š” ์ƒ๋žต ๊ฐ€๋Šฅํ•˜๋‹ค.

1
SELECT m FROM Member m INNER JOIN m.team t WHERE t.name = :teamName

Outer Join

์—ฐ๊ด€๊ด€๊ณ„๊ฐ€ ์—†๋”๋ผ๋„ ๊ธฐ์ค€์ด ๋˜๋Š” ์—”ํ‹ฐํ‹ฐ์˜ ๋ฐ์ดํ„ฐ๋ฅผ ๋ชจ๋‘ ํฌํ•จํ•˜์—ฌ ์กฐํšŒํ•œ๋‹ค. ๋ฐ์ดํ„ฐ๊ฐ€ ์—†๋Š” ๊ฒฝ์šฐ NULL ๋กœ ํ‘œ์‹œ๋œ๋‹ค. OUTER ํ‚ค์›Œ๋“œ๋Š” ์ƒ๋žต ๊ฐ€๋Šฅํ•˜๋‹ค.

1
SELECT m FROM Member m LEFT OUTER JOIN m.team t

Theta Join

์—ฐ๊ด€๊ด€๊ณ„ ์—†๋Š” ์—”ํ‹ฐํ‹ฐ ๊ฐ„์—๋„ WHERE์ ˆ์„ ๋งŒ์กฑํ•˜๋Š” ๋ฐ์ดํ„ฐ๋ฅผ ์กฐ์ธํ•œ๋‹ค.

1
SELECT m FROM Member m, Team t WHERE m.username = t.name

JPA 2.1๋ถ€ํ„ฐ ON ์ ˆ์„ ์‚ฌ์šฉํ•˜์—ฌ ์กฐ์ธ ๋Œ€์ƒ์„ ํ•„ํ„ฐ๋งํ•  ์ˆ˜ ์žˆ๋‹ค.

1
SELECT m FROM Member m LEFT JOIN m.team t ON t.name = 'A'

Fetch Join

Fetch Join ์€ JPQL์—์„œ ์„ฑ๋Šฅ ์ตœ์ ํ™”๋ฅผ ์œ„ํ•ด ์ œ๊ณตํ•˜๋Š” ๊ธฐ๋Šฅ์ด๋‹ค. Fetch Join์„ ํ†ตํ•ด ์—ฐ๊ด€๋œ ์—”ํ‹ฐํ‹ฐ๋‚˜ ์ปฌ๋ ‰์…˜์„ ํ”„๋ก์‹œ ๊ฐ์ฒด๊ฐ€ ์•„๋‹Œ ์‹ค์ œ ๋ฐ์ดํ„ฐ๋กœ SQL ์ฟผ๋ฆฌ์™€ ํ•จ๊ป˜ ์กฐํšŒํ•˜์—ฌ ๋กœ๋”ฉํ•  ์ˆ˜ ์žˆ๋‹ค. ์ด๋ฅผ ํ†ตํ•ด N+1 ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•  ์ˆ˜ ์žˆ๋‹ค.

JOIN FETCH ๋ผ๋Š” ํ‚ค์›Œ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜๋ฉฐ, ์กฐํšŒ ์ฃผ์ฒด๊ฐ€ ๋˜๋Š” ์—”ํ‹ฐํ‹ฐ๋ฟ๋งŒ ์•„๋‹ˆ๋ผ FETCH๋กœ ๋ช…์‹œ๋œ ์—ฐ๊ด€ ์—”ํ‹ฐํ‹ฐ๊นŒ์ง€ ํ•จ๊ป˜ ์กฐํšŒํ•˜์—ฌ ์ฆ‰์‹œ ๋กœ๋”ฉ(Eager Loading) ํ›„ ์˜์†ํ™”ํ•œ๋‹ค.

@ManyToOne, @OneToOne ๊ด€๊ณ„์—์„œ ์‚ฌ์šฉํ•˜๋Š” ํŽ˜์น˜ ์กฐ์ธ์„ ์—”ํ‹ฐํ‹ฐ ํŽ˜์น˜ ์กฐ์ธ, @OneToMany ๊ด€๊ณ„์—์„œ ์‚ฌ์šฉํ•˜๋Š” ํŽ˜์น˜ ์กฐ์ธ์„ ์ปฌ๋ ‰์…˜ ํŽ˜์น˜ ์กฐ์ธ์ด๋ผ๊ณ  ํ•œ๋‹ค.

1
2
3
4
5
-- ์—”ํ‹ฐํ‹ฐ ํŽ˜์น˜ ์กฐ์ธ
SELECT m FROM Member m JOIN FETCH m.team

-- ์ปฌ๋ ‰์…˜ ํŽ˜์น˜ ์กฐ์ธ
SELECT t FROM Team t JOIN FETCH t.members

์ปฌ๋ ‰์…˜ ํŽ˜์น˜ ์กฐ์ธ ์‹œ ๋ฐ์ดํ„ฐ ์ค‘๋ณต์ด ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ๋‹ค. ์ด๋ฅผ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด DISTINCT ํ‚ค์›Œ๋“œ๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค. ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ๋ ˆ๋ฒจ์—์„œ ์—”ํ‹ฐํ‹ฐ์˜ ์‹๋ณ„์ž๋ฅผ ๊ธฐ์ค€์œผ๋กœ ์ค‘๋ณต๋œ ์—”ํ‹ฐํ‹ฐ๋ฅผ ์ œ๊ฑฐํ•œ๋‹ค.

ํŽ˜์น˜ ์กฐ์ธ์€ FetchType ๊ฐ™์€ ๊ธ€๋กœ๋ฒŒ ๋กœ๋”ฉ ์ „๋žต๋ณด๋‹ค ์šฐ์„ ์ˆœ์œ„๊ฐ€ ๋†’๋‹ค. ๋ณดํ†ต ์—”ํ‹ฐํ‹ฐ ๋กœ๋”ฉ ์ „๋žต์„ fetch = FetchType.LAZY ๋กœ ์„ค์ •ํ•˜๊ณ  ํ•„์š”ํ•œ ๊ฒฝ์šฐ ํŽ˜์น˜ ์กฐ์ธ์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒฝ์šฐ๊ฐ€ ๋งŽ๋‹ค. ๋˜ํ•œ ํŽ˜์น˜ ์กฐ์ธ ๋Œ€์ƒ์—๋Š” ๋ณ„์นญ์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์—†๋‹ค. ๋‘˜ ์ด์ƒ์˜ ์ปฌ๋ ‰์…˜์„ ํŽ˜์น˜ ์กฐ์ธํ•  ์ˆ˜ ์—†์œผ๋ฉฐ, ํŽ˜์ด์ง• API๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์—†๋‹ค.

์ผ๋ฐ˜ ์กฐ์ธ๊ณผ ํŽ˜์น˜ ์กฐ์ธ์˜ ๊ฐ€์žฅ ํฐ ์ฐจ์ด์ ์€ ์—ฐ๊ด€ ์—”ํ‹ฐํ‹ฐ์˜ ์กฐํšŒ ๋ฐ ์˜์†ํ™” ์—ฌ๋ถ€์ด๋‹ค. ์ผ๋ฐ˜ ์กฐ์ธ์€ ์—ฐ๊ด€ ์—”ํ‹ฐํ‹ฐ๋ฅผ ๋กœ๋”ฉํ•˜์ง€ ์•Š์œผ๋ฉฐ ์˜์†ํ™”ํ•˜์ง€ ์•Š๋Š”๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ํŽ˜์น˜ ์กฐ์ธ์€ ์—ฐ๊ด€ ์—”ํ‹ฐํ‹ฐ๋ฅผ ํ•จ๊ป˜ ๋กœ๋”ฉํ•˜์—ฌ ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ์— ๋กœ๋”ฉํ•œ๋‹ค.

๐Ÿ“Œ @Query

JPA์—์„œ @Query ์–ด๋…ธํ…Œ์ด์…˜์„ ํ†ตํ•ด ์ง์ ‘ JPQL ๋˜๋Š” Native SQL ์ฟผ๋ฆฌ๋ฅผ ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ๋‹ค.

1
2
3
4
public interface UserRepository extends JpaRepository<User, Long> {
    @Query("SELECT u FROM User u WHERE u.status = 1")
    Collection<User> findAllActiveUsers();
}

nativeQuery = true ์†์„ฑ์„ ํ†ตํ•ด Native SQL ์ฟผ๋ฆฌ๋ฅผ ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ๋‹ค.

1
2
3
4
5
6
public interface UserRepository extends JpaRepository<User, Long> {
    @Query(
      value = "SELECT * FROM USERS u WHERE u.status = 1",
      nativeQuery = true)
    Collection<User> findAllActiveUsersNative();
}

๋ฉ”์„œ๋“œ์˜ ํŒŒ๋ผ๋ฏธํ„ฐ์— @Param ์–ด๋…ธํ…Œ์ด์…˜์„ ํ†ตํ•ด JPQL ๋‚ด์˜ ํŒŒ๋ผ๋ฏธํ„ฐ ์ด๋ฆ„๊ณผ ๋งคํ•‘ํ•  ์ˆ˜ ์žˆ๋‹ค.

1
2
3
4
public interface MemberRepository extends JpaRepository<Member, Long> {
    @Query("select m from Member m where m.username = :name")
    Member findMembers(@Param("name") String username);
}

INSERT, UPDATE, DELETE์™€ ๊ฐ™์€ DML ์ฟผ๋ฆฌ๋ฅผ ์‚ฌ์šฉํ•  ๋•Œ, @Modifying ์–ด๋…ธํ…Œ์ด์…˜์„ ํ•จ๊ป˜ ์‚ฌ์šฉํ•ด์•ผ ํ•œ๋‹ค.

1
2
3
4
5
6
public interface UserRepository extends JpaRepository<User, Long> {
    @Transactional
    @Modifying
    @Query("update User u set u.name = :name where u.id = :id")
    int updateName(@Param("id") Long id, @Param("name") String name); // ๋ฒŒํฌ ์—ฐ์‚ฐ์€ ์—…๋ฐ์ดํŠธ๋œ ํ–‰ ์ˆ˜๋ฅผ ๋ฐ˜ํ™˜
}

๐Ÿ“Œ ์ฐธ๊ณ 

https://ittrue.tistory.com/270

https://adjh54.tistory.com/479

https://ict-nroo.tistory.com/116

https://velog.io/@kevin_/JPQL

This post is licensed under CC BY 4.0 by the author.