๐ŸŒฑSpring Data JPA

Dohyeon Kongยท2024๋…„ 6์›” 16์ผ
1

Spring๐ŸŒฑ

๋ชฉ๋ก ๋ณด๊ธฐ
6/11
post-thumbnail

JPA์™€ Hibernate

JPA

JPA(Java Persistence API)๋Š” ์ž๋ฐ” ์ง„์˜์˜ ORM(Object-Relational Mapping) ๊ธฐ์ˆ  ํ‘œ์ค€์œผ๋กœ ์ฑ„ํƒ๋œ ์ธํ„ฐํŽ˜์ด์Šค(Interface)์˜ ๋ชจ์Œ์ด๋‹ค.

์—ฌ๊ธฐ์„œ ์šฐ๋ฆฌ๋Š” 'ORM'์ด๋ผ๋Š” ๋‹จ์–ด๋ฅผ ๊ฐ„๋‹จํ•˜๊ฒŒ ์‚ดํŽด๋ณด๋ฉด ๊ฐ์ฒด ์ง€ํ–ฅ ์–ธ์–ด์—์„œ ์˜๋ฏธํ•˜๋Š” ๊ฐ์ฒด(ํด๋ž˜์Šค)์™€ RDB์˜ ํ…Œ์ด๋ธ”์„ ์ž๋™์œผ๋กœ ๋งคํ•‘(Mapping)ํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ์˜๋ฏธํ•œ๋‹ค.

๊ฐ์ฒด ์ง€ํ–ฅ ํ”„๋กœ๊ทธ๋ž˜๋ฐ์—์„œ๋Š” ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ์ฒด ํ˜•ํƒœ๋กœ ๋‹ค๋ฃจ๊ณ , RDB๋Š” ๋ฐ์ดํ„ฐ๋ฅผ ํ…Œ์ด๋ธ” ํ˜•ํƒœ๋กœ ์ €์žฅํ•œ๋‹ค. ์ด ๋‘ ์‹œ์Šคํ…œ ๊ฐ„์—๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์€ ๋ถˆ์ผ์น˜๊ฐ€ ์กด์žฌํ•œ๋‹ค.

Object์™€ RDB์˜ ์กด์žฌํ•˜๋Š” ๋ถˆ์ผ์น˜

  • ์ƒ์† : ๊ฐ์ฒด ์ง€ํ–ฅ ์–ธ์–ด์—์„œ๋Š” ์ƒ์†์„ ํ†ตํ•ด ๊ณ„์ธต ๊ตฌ์กฐ๋ฅผ ๋งŒ๋“ค ์ˆ˜ ์žˆ์ง€๋งŒ, RDB์—๋Š” ์ƒ์† ๊ฐœ๋…์ด ์—†๋‹ค.
  • ์—ฐ๊ด€ ๊ด€๊ณ„ : ๊ฐ์ฒด ๊ฐ„์˜ ์—ฐ๊ด€ ๊ด€๊ณ„(1:1, 1,N ๋“ฑ)๋ฅผ ํ‘œํ˜„ํ•˜๋Š” ๋ฐฉ๋ฒ•์ด ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์˜ ์™ธ๋ž˜ ํ‚ค์™€๋Š” ๋‹ค๋ฅด๋‹ค.
  • ์‹๋ณ„์ž : ๊ฐ์ฒด๋Š” ์ฃผ๋กœ ์ฐธ์กฐ๋ฅผ ํ†ตํ•ด ์‹๋ณ„๋˜์ง€๋งŒ, ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค๋Š” ์ฃผ๋กœ ๊ธฐ๋ณธ ํ‚ค๋ฅผ ํ†ตํ•ด ์‹๋ณ„๋œ๋‹ค.
  • ๋ฐ์ดํ„ฐ ํƒ€์ž… : ๊ฐ์ฒด์™€ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์˜ ๋ฐ์ดํ„ฐ ํƒ€์ž…์ด ๋‹ค๋ฅผ ์ˆ˜ ์žˆ๋‹ค.

=> ์ฆ‰. ์ด๋Ÿฌํ•œ ๋‘˜ ์‚ฌ์ด๊ฐ„์˜ ๋ถˆ์ผ์น˜์„ฑ์„ ํ•ด๊ฒฐํ•˜๋Š” ์—ญํ• ์ด ๋ฐ”๋กœ ORM์ด๋‹ค.

JPA๋Š” ์ด๋Ÿฌํ•œ ORM์„ ๊ตฌํ˜„ํ•˜๊ธฐ ์œ„ํ•œ ํ‘œ์ค€ ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ์ œ๊ณตํ•˜๋ฉฐ, JPA๋ฅผ ๊ตฌํ˜„ํ•œ ๋Œ€ํ‘œ์ ์ธ ๊ตฌํ˜„์ฒด๋กœ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์„ธ๊ฐ€์ง€๋“ค์ด ์žˆ๋‹ค.

JPA์˜ ๊ตฌํ˜„์ฒด์˜ ์ข…๋ฅ˜

  • EclipseLink
  • Hibernate
    (๊ฐ€์žฅ ๋„๋ฆฌ ์‚ฌ์šฉ๋˜๋Š” JPA ๊ตฌํ˜„์ฒด๋กœ, ๋‹ค์–‘ํ•œ ๊ธฐ๋Šฅ๊ณผ ๋†’์€ ํ˜ธํ™˜์„ฑ์„ ์ž๋ž‘ํ•œ๋‹ค.)
  • DataNucleus

Hibernate

Hibernate(ํ•˜์ด๋ฒ„๋„ค์ดํŠธ)๋Š” ์ž๋ฐ”์˜ ORM ํ”„๋ ˆ์ž„์›Œํฌ๋กœ์„œ, JPA๊ฐ€ ์ •์˜ํ•˜๋Š” ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ๊ตฌํ˜„ํ•˜๊ณ  ์žˆ๋Š” JPA ๊ตฌํ˜„์ฒด ์ค‘ ํ•˜๋‚˜์ด๋‹ค.

Hibernate๋Š” ๊ฐ์ฒด์™€ ๊ด€๊ณ„ํ˜• ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ๊ฐ„์˜ ๋งคํ•‘์„ ๊ด€๋ฆฌํ•˜๋ฉฐ, ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์™€์˜ ์ƒํ˜ธ์ž‘์šฉ์„ ๊ฐ„์†Œํ™”ํ•œ๋‹ค. ๋˜ํ•œ, Query๋ฌธ๋“ค์„ ์ฝ˜์†”์ฐฝ์—์„œ ํ™•์ธํ•˜๊ณ  ์‹ถ์œผ๋ฉด, ๋‹ค์Œ๊ณผ ๊ฐ™์€ ์„ค์ •์„ application.properties ํŒŒ์ผ์— ์ถ”๊ฐ€ํ•˜๋ฉด ๋œ๋‹ค.

// ์ฟผ๋ฆฌ ๋กœ๊ทธ Show๋ฅผ true๋กœ ์„ค์ •
// ์‹คํ–‰๋˜๋Š” SQL ์ฟผ๋ฆฌ๋ฅผ ์ฝ˜์†”์— ์ถœ๋ ฅํ•œ๋‹ค.
spring.jpa.show-sql=true 

// SQL๋ฌธ์„ ์ •๋ ฌํ•˜์—ฌ ์ถœ๋ ฅ
// ์ฆ‰, ์ถœ๋ ฅ๋˜๋Š” SQL ์ฟผ๋ฆฌ๋ฅผ ๋ณด๊ธฐ ์‰ฝ๊ฒŒ ํฌ๋งทํŒ…ํ•œ๋‹ค.
spring.jpa.properties.hibernate.format_sql=true 


// ๋ฐ”์ธ๋”ฉ๋˜๋Š” ํŒŒ๋ผ๋ฏธํ„ฐ ๊ฐ’์„ ์ถœ๋ ฅ
logging.level.org.hibernate.type.descriptor.sql=trace


Spring Data JPA

JPA๋ฅผ ํŽธ๋ฆฌํ•˜๊ฒŒ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋„๋ก ์ง€์›ํ•˜๋Š” ์Šคํ”„๋ง ํ•˜์œ„ ํ”„๋กœ์ ํŠธ ์ค‘ ํ•˜๋‚˜์ด๋‹ค. CRUD ์ฒ˜๋ฆฌ์— ํ•„์š”ํ•œ ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ์ œ๊ณตํ•˜๊ณ  Hibernate์˜ ์—”ํ‹ฐํ‹ฐ ๋งค๋‹ˆ์ €๋ฅผ ์ง์ ‘ ๋‹ค๋ฃจ์ง€ ์•Š๊ณ ๋„ Repository๋ฅผ ์ •์˜ํ•ด ์‚ฌ์šฉํ•จ์œผ์จ ์Šคํ”„๋ง์ด ์ ํ•ฉํ•œ ์ฟผ๋ฆฌ๋ฅผ ๋™์ ์œผ๋กœ ์ƒ์„ฑํ•˜๋Š” ๋ฐฉ์‹์œผ๋กœ DB๋ฅผ ์กฐ์ž‘ํ•œ๋‹ค.

Spring Data JPA์˜ ์ฃผ์š” ๊ธฐ๋Šฅ

์ด๋ฒˆ ๊ธ€์—์„œ ๋‹ค๋ฃจ๋Š” Spring Data JPA ๊ธฐ๋Šฅ์€ ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค.

  • JPQL(Java Persistence Query Language)
  • Query Method
  • ์ •๋ ฌ๊ณผ ํŽ˜์ด์ง• ์ฒ˜๋ฆฌ
  • @Query annotation
  • QueryDSL

JPQL(Java Persistence Query Language)

JPA์—์„œ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ์ฟผ๋ฆฌ๋ฅผ ์˜๋ฏธํ•œ๋‹ค.

JPQL์˜ ๋ฌธ๋ฒ•์ด SQL ๋ฌธ๋ฒ•๊ณผ ๋งค์šฐ ๋น„์Šทํ•˜์—ฌ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์ฟผ๋ฆฌ์— ์ต์ˆ™ํ•œ ๋ถ„๋“ค์ด ์–ด๋ ต์ง€ ์•Š๊ฒŒ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค. JPQL์€ ์—”ํ‹ฐํ‹ฐ ๊ฐ์ฒด๋ฅผ ๋Œ€์ƒ์œผ๋กœ ์ˆ˜ํ–‰ํ•˜๋Š” ์ฟผ๋ฆฌ์ด๋ฏ€๋กœ ๋งคํ•‘๋œ ์—”ํ‹ฐํ‹ฐ์˜ ์ด๋ฆ„๊ณผ ํ•„๋“œ์˜ ์ด๋ฆ„์„ ์‚ฌ์šฉํ•œ๋‹ค.

// JPQL Basic Example
SELECT P FROM PRODUCT P WHERE P.NUMBER = ?1;

// PRODUCT๋Š” ์—”ํ‹ฐํ‹ฐ ํƒ€์ž…, NUMBER๋Š” ์—”ํ‹ฐํ‹ฐ ๊ฐ์ฒด์˜ ์†์„ฑ์„ ์˜๋ฏธํ•œ๋‹ค.
// 1์€ ์ฒซ ๋ฒˆ์งธ ํŒŒ๋ผ๋ฏธํ„ฐ ์˜๋ฏธํ•œ๋‹ค. (์—ฌ๊ธฐ์„œ๋Š” ๋งค๊ฐœ๋ณ€์ˆ˜๋กœ ๋ฐ›์€ number์˜ ๊ฐ’์ด ๋“ค์–ด๊ฐˆ ๊ฒƒ์ด๋‹ค.)

Query Method

๋ฆฌํฌ์ง€ํ„ฐ๋ฆฌ์—์„œ ๊ธฐ๋ณธ์œผ๋กœ ์ œ๊ณต๋˜๋Š” ๋ฉ”์„œ๋“œ์™ธ ๋ณ„๋„์˜ ๋ฉ”์„œ๋“œ๋ฅผ ์ •์˜ํ•ด์•ผ ํ•˜๋Š” ๊ฒฝ์šฐ ์ฟผ๋ฆฌ๋ฌธ์„ ์ž‘์„ฑํ•˜๊ธฐ ์œ„ํ•ด ์‚ฌ์šฉ๋˜๋Š” ๊ฒƒ์ด ๋ฐ”๋กœ Query Method์ด๋‹ค.

์šฐ๋ฆฌ๊ฐ€ ์‚ฌ์šฉํ•˜๋Š” Repository ์ธํ„ฐํŽ˜์ด์Šค๋Š” ๊ธฐ๋ณธ์ ์œผ๋กœ JpaRepository๋ฅผ ๊ตฌํ˜„๋ฐ›์•„์„œ ๋‹ค์–‘ํ•œ CRUD ๋ฉ”์„œ๋“œ๋ฅผ ์ œ๊ณตํ•œ๋‹ค. Query Method๋Š” ํฌ๊ฒŒ ๋™์ž‘์„ ๊ฒฐ์ •ํ•˜๋Š” Subject(์ฃผ์ œ) + Predicate(๋™์ž‘)์œผ๋กœ ๊ตฌ๋ถ„ํ•œ๋‹ค.

'findBy...'์™€ 'getBy...' ๋“ฑ์ด Subject(์ฃผ์ œ)๋ฅผ ๋‚˜ํƒ€๋‚ด๋ฉฐ, By๋Š” Predicate(๋™์ž‘)์˜ ์‹œ์ž‘์„ ๋‚˜ํƒ€๋‚ด์–ด ๊ตฌ๋ถ„์ž์˜ ์—ญํ• ์„ ํ•œ๋‹ค.

// ๋ฆฌํฌ์ง€ํ„ฐ๋ฆฌ์˜ ์ฟผ๋ฆฌ ๋ฉ”์„œ๋“œ ์ƒ์„ฑ ์˜ˆ
List<Person> findByLastNameAndEmail(String lastName, String Email);

// ๋ฉ”์„œ๋“œ ๋ช…์— ๋“ค์–ด๊ฐ€์žˆ๋Š” By ์ดํ›„์˜ LastName๊ณผ Email์ด ๋ฉ”์„œ๋“œ์˜ ๋งค๊ฐœ๋ณ€์ˆ˜๋กœ ๋“ค์–ด๊ฐ€ ์žˆ๋‹ค.

์„œ์ˆ ์–ด์— ๋“ค์–ด๊ฐˆ ์—”ํ‹ฐํ‹ฐ์˜ ์†์„ฑ ์‹์€ ์—”ํ‹ฐํ‹ฐ์—์„œ ๊ด€๋ฆฌํ•˜๋Š” ํ•„๋“œ๋งŒ ์ฐธ์กฐํ•  ์ˆ˜ ์žˆ๋‹ค.

Query Method์˜ ์ฃผ์ œ ํ‚ค์›Œ๋“œ

๋™์‚ฌ์™€ By ์‚ฌ์ด์˜ ๋„๋ฉ”์ธ์ด ํ‘œํ˜„๋  ์ˆ˜ ์žˆ์ง€๋งŒ repository์—์„œ ์ด๋ฏธ ์„ค์ •ํ•œ ํ›„์ด๊ธฐ ๋•Œ๋ฌธ์— ์ƒ๋žต ๊ฐ€๋Šฅํ•˜๋‹ค.

  1. ์กฐํšŒํ•˜๋Š” ๊ธฐ๋Šฅ์„ ์ˆ˜ํ–‰ํ•˜๋Š” ํ‚ค์›Œ๋“œ
- findBy...
- readBy...
- getBy...
- queryBy...
- searchBy...
- streamBy...
  • return type์œผ๋กœ Collection์ด๋‚˜ Stream์— ์†ํ•œ ํ•˜์œ„ ํƒ€์ž…์„ ์„ค์ •ํ•  ์ˆ˜ ์žˆ๋‹ค.
  1. ํŠน์ • ๋ฐ์ดํ„ฐ ์กด์žฌ ์œ ๋ฌด๋ฅผ ํ™•์ธํ•˜๋Š” ํ‚ค์›Œ๋“œ
- existsBy...

// Example
boolean existsByNumber(Long number);
  • return type์œผ๋กœ boolean์„ ์‚ฌ์šฉํ•œ๋‹ค.
  1. ์‚ญ์ œ ์ฟผ๋ฆฌ๋ฅผ ์ˆ˜ํ–‰ํ•˜๋Š” ํ‚ค์›Œ๋“œ
- deleteBy...
- removeBy...

// Example
void deleteByNumber(Long number);
long removeByName(String name);
  • return type์œผ๋กœ void๋‚˜ ์ •์ˆ˜ํ˜•(์‚ญ์ œ๋œ ๊ฐฏ์ˆ˜)์„ ๋ฐ˜ํ™˜ํ•œ๋‹ค.
  1. ์ฟผ๋ฆฌ๋ฅผ ํ†ตํ•ด ์กฐํšŒ๋œ ๊ฒฐ๊ณผ๊ฐ’์˜ ๊ฐœ์ˆ˜๋ฅผ ์ œํ•œํ•˜๋Š” ํ‚ค์›Œ๋“œ
- findFirst์ˆซ์žBy...
- findTop์ˆซ์žBy...

// Example
List<Product> findFirst5ByName(String name);
List<Product> findTop10ByName(String name);
  • ๋‘ ํ‚ค์›Œ๋“œ๋Š” ๋™์ผํ•œ ๋™์ž‘์„ ์ˆ˜ํ–‰ํ•œ๋‹ค.
  • ์ฃผ์ œ์™€ By์‚ฌ์ด์— ์œ„์น˜ํ•˜๋ฉฐ, ํ•œ ๋ฒˆ์˜ ๋™์ž‘์œผ๋กœ ์—ฌ๋Ÿฌ ๊ฑด์„ ์กฐํšŒํ•  ๋•Œ ์‚ฌ์šฉํ•œ๋‹ค.
  • ํ•˜๋‚˜์˜ ๊ฑด์œผ๋กœ ์กฐํšŒํ•˜๋Š” ๊ฒƒ์€ ์ˆซ์ž๋ฅผ ์ƒ๋žตํ•˜๋ฉด ๋œ๋‹ค.

Query Method์˜ ์กฐ๊ฑด์ž ํ‚ค์›Œ๋“œ

Spring Data JPA์˜ ๋ฉ”์†Œ๋“œ ์ด๋ฆ„ ๊ธฐ๋ฐ˜ ์ฟผ๋ฆฌ ์ž‘์„ฑ ๋ฐฉ์‹์—์„œ ์กฐ๊ฑด์‹์„ ๋œปํ•˜๋Š” ๋‹จ์–ด๋ฅผ ํฌํ•จํ•ด์„œ ์‚ฌ์šฉ๋˜๋Š” ํ‚ค์›Œ๋“œ๋ฅผ ์˜๋ฏธํ•œ๋‹ค.

  • ์ฑ…์—์„œ์˜ ์• ๋งคํ•œ ํ‘œํ˜„ : 'JPQL์˜ ์„œ์ˆ ์–ด ๋ถ€๋ถ„์—์„œ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ํ‚ค์›Œ๋“œ'๋ผ๊ณ  ๋‚˜์™€์žˆ๋Š”๋ฐ JPQL์˜ ์„œ์ˆ ์–ด ๋ถ€๋ถ„์—์„œ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ํ‚ค์›Œ๋“œ๋Š” JPQL ์ฟผ๋ฆฌ์˜ WHERE ์ ˆ์—์„œ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ์กฐ๊ฑด์ž๋ฅผ ์˜๋ฏธํ•œ๋‹ค.
  1. ๊ฐ’์˜ ์ผ์น˜๋ฅผ ์กฐ๊ฑด์œผ๋กœ ์‚ฌ์šฉํ•˜๋Š” ์กฐ๊ฑด์ž ํ‚ค์›Œ๋“œ
- ..IS

// Example
Product findByNumberIS(Long number);
Product findByNumberEquals(Long number);
  1. ๊ฐ’์˜ ๋ถˆ์ผ์น˜๋ฅผ ์กฐ๊ฑด์œผ๋กœ ์‚ฌ์šฉํ•˜๋Š” ์กฐ๊ฑด์ž ํ‚ค์›Œ๋“œ
- ..(Is)Not

// Example
Product findByNumberIsNot(Long number);
Product findByNumberNot(Long number);
  • Is ์ƒ๋žตํ•˜๊ณ  Notํ‚ค์›Œ๋“œ๋งŒ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.
  1. ๊ฐ’์ด Null์ธ์ง€ ๊ฒ€์‚ฌํ•˜๋Š” ์กฐ๊ฑด์ž ํ‚ค์›Œ๋“œ
- ..(Is)Null
- ..(Is)NotNull

// Example
List<Product> findByUpdatedAtNull();
List<Product> findByUpdatedAtIsNull();
List<Product> findByUpdatedAtNotNull();
List<Product> findByUpdatedAtIsNotNull();
  1. booleanํƒ€์ž…์œผ๋กœ ์ง€์ •๋œ ์ปฌ๋Ÿผ๊ฐ’์„ ํ™•์ธํ•˜๋Š” ํ‚ค์›Œ๋“œ
- ..(Is)True
- ..(Is)False

// Example
Product findByActiveTrue();
Product findByActiveIsTrue();
Product findByActiveFalse();
Product findByActiveIsFalse();
  1. ์—ฌ๋Ÿฌ ์กฐ๊ฑด์„ ๋ฌถ์„ ๋•Œ ์‚ฌ์šฉํ•˜๋Š” ํ‚ค์›Œ๋“œ
- And
- Or

// Example
Product findByNumberAndName(Long number, String name);
Product findByNumberOrName(Long number, String name);
  1. ์ˆซ์ž๋‚˜ datetime ์ปฌ๋Ÿผ์„ ๋Œ€์ƒ์œผ๋กœ ํ•˜๋Š” ๋น„๊ต ์—ฐ์‚ฐ ์‹œ ์‚ฌ์šฉํ•˜๋Š” ํ‚ค์›Œ๋“œ
- ..(Is)GreaterThan
- ..(Is)LessThan
- ..(Is)Between

// Example
List<Product> findByPriceGreaterThan(Long price);
List<Product> findByPriceLessThan(Long price);
List<Product> findByPriceBetween(Long startPrice, Long endPrice);List<Product> findByPriceLessThanEqual(Long startPrice, Long endPrice);
  • GreaterThan๊ณผ LessThan ํ‚ค์›Œ๋“œ๋Š” ๋น„๊ต ๋Œ€์ƒ์— ๋Œ€ํ•œ ์ดˆ๊ณผ/๋ฏธ๋งŒ์˜ ๊ฐœ๋…์œผ๋กœ ๋น„๊ต ์—ฐ์‚ฐ์„ ์ˆ˜ํ–‰ํ•œ๋‹ค.
  • ๊ฒฝ๊ณ„๊ฐ’๊นŒ์ง€ ํฌํ•จ์‹œํ‚ค๊ณ  ์‹ถ์œผ๋ฉด Equal ํ‚ค์›Œ๋“œ๋ฅผ ์ถ”๊ฐ€ํ•˜๋ฉด ๋œ๋‹ค.
  1. ์ปฌ๋Ÿผ๊ฐ’์—์„œ ์ผ๋ถ€ ์ผ์น˜ ์—ฌ๋ถ€๋ฅผ ํ™•์ธํ•˜๋Š” ํ‚ค์›Œ๋“œ
- ..(Is)StartingWith
- ..(Is)EndingWith
- ..(Is)Containing
- ..(Is)Like

// Example
List<Customer> findByFirstNameStartingWith(String prefix);
List<Customer> findByLastNameEndingWith(String suffix);
List<Customer> findByFirstNameContaining(String infix);
List<Customer> findByLastNameLike(String pattern);

// Service๋‹จ์—์„œ ์‚ฌ์šฉ๋˜๋Š” ์˜ˆ
List<Customer> customers = customerRepository.findByFirstNameStartingWith("Jo");
// John, Johnny, Joanna
List<Customer> customers = customerRepository.findByLastNameEndingWith("son");
// Johnson, Jackson, Harrison
List<Customer> customers = customerRepository.findByFirstNameContaining("ann");
// Joanna, Annabelle, Hannah
List<Customer> customers = customerRepository.findByLastNameLike("%son%");
// Johnson, Jackson, Harrison
  • SQL ์ฟผ๋ฆฌ๋ฌธ์—์„œ ๊ฐ’์˜ ์ผ๋ถ€๋ฅผ ํฌํ•จํ•˜๋Š” ๊ฐ’์„ ์ถ”์ถœํ•  ๋•Œ ์‚ฌ์šฉํ•˜๋Š” '%'์™€ ๋™์ผํ•œ ์—ญํ• ์„ ํ•˜๋Š” ํ‚ค์›Œ๋“œ์ด๋‹ค.
  • ์ž๋™์œผ๋กœ ์ƒ์„ฑ๋˜๋Š” SQL๋ฌธ์„ ๋ณด๋ฉด StartingWith ํ‚ค์›Œ๋“œ๋Š” ๋ฌธ์ž์—ด ์•ž, EndingWith ํ‚ค์›Œ๋“œ๋Š” ๋ฌธ์ž์—ด ๋, Containing ํ‚ค์›Œ๋“œ๋Š” ๋ฌธ์ž์—ด์˜ ์–‘๋์— '%'๊ฐ€ ์ž๋™์œผ๋กœ ๋ฐฐ์น˜๋œ๋‹ค.
  • ํ•˜์ง€๋งŒ! Likeํ‚ค์›Œ๋“œ๋Š” ๋ช…์‹œ์ ์œผ๋กœ '%'๋ฅผ ์ž…๋ ฅํ•ด์•ผ ํ•œ๋‹ค.

์ •๋ ฌ๊ณผ ํŽ˜์ด์ง• ์ฒ˜๋ฆฌ

Query Method๋ฅผ ํ†ตํ•œ ์ •๋ ฌ ์ฒ˜๋ฆฌ

// ์ฟผ๋ฆฌ ๋ฉ”์„œ๋“œ์˜ ์ •๋ ฌ ์ฒ˜๋ฆฌ
// Asc : ์˜ค๋ฆ„์ฐจ์ˆœ, Desc : ๋‚ด๋ฆผ์ฐจ์ˆœ
List<Product> findByNameOrderByNumberAsc(String name);
List<Product> findByNameOrderByNumberDesc(String name);
  • ๊ธฐ๋ณธ ์ฟผ๋ฆฌ ๋ฉ”์„œ๋“œ(findByName)๋ฅผ ์ž‘์„ฑํ•œ ํ›„ OrderBy ํ‚ค์›Œ๋“œ๋ฅผ ์‚ฝ์ž…ํ•˜์—ฌ ์ •๋ ฌํ•˜๊ณ ์ž ํ•˜๋Š” ์ปฌ๋Ÿผ(Number)๊ณผ ์˜ค๋ฆ„์ฐจ์ˆœ/๋‚ด๋ฆผ์ฐจ์ˆœ(Asc ํ˜น์€ Desc)์„ ์„ค์ •ํ•˜๋ฉด ์ •๋ ฌ์ด ์ˆ˜ํ–‰๋œ๋‹ค.
  • List<Product> findByNameOrderByNumberAsc(String name); ์˜ Query Method๋ฅผ ํ•ด์„ํ•˜๋ฉด '์ƒํ’ˆ ์ •๋ณด๋ฅผ ์ด๋ฆ„์œผ๋กœ ๊ฒ€์ƒ‰ํ•œ ํ›„ ์ƒํ’ˆ ๋ฒˆํ˜ธ๋กœ ์˜ค๋ฆ„์ฐจ์ˆœ ์ •๋ ฌ์„ ์ˆ˜ํ–‰ํ•œ๋‹ค.'๋Š” ์˜๋ฏธ์ด๋‹ค.
  • List<Product> findByNameOrderByNumberDesc(String name); ์˜ Query Method๋ฅผ ํ•ด์„ํ•˜๋ฉด '์ƒํ’ˆ ์ •๋ณด๋ฅผ ์ด๋ฆ„์œผ๋กœ ๊ฒ€์ƒ‰ํ•œ ํ›„ ์ƒํ’ˆ ๋ฒˆํ˜ธ์˜ ๋‚ด๋ฆผ์ฐจ์ˆœ ์ •๋ ฌ์„ ์ˆ˜ํ–‰ํ•œ๋‹ค.'๋Š” ์˜๋ฏธ์ด๋‹ค.
// ์ฟผ๋ฆฌ ๋ฉ”์„œ๋“œ์—์„œ ์—ฌ๋Ÿฌ ์ •๋ ฌ ๊ธฐ์ค€ ์‚ฌ์šฉ
// And๋ฅผ ๋ถ™์ด์ง€ ์•Š์Œ
List<Prodcut> findByNameOrderByPriceAscStockDesc(String name);
List<Product> findByNameOrderByPrice(String name);
// List<Prodcut> findByNameOrderByPriceAscStockDesc(String name)์˜ hibernate
Hibernate: 
    select
        product0_.id as id1_0_,
        product0_.name as name2_0_,
        product0_.price as price3_0_,
        product0_.stock as stock4_0_
    from
        product product0_
    where
        product0_.name=?
    order by
        product0_.price asc,
        product0_.stock desc
  • ์œ„์ฒ˜๋Ÿผ ์ •๋ ฌ ํ‚ค์›Œ๋“œ๋ฅผ ์‚ฝ์ž…ํ•ด์„œ ์ •๋ ฌ์„ ์ˆ˜ํ–‰ํ•˜๋Š” ๊ฒƒ๋„ ๊ฐ€๋Šฅํ•˜์ง€๋งŒ ๋ฉ”์„œ๋“œ์˜ ์ด๋ฆ„์ด ๊ธธ์–ด์งˆ์ˆ˜๋ก ๊ฐ€๋…์„ฑ์ด ๋–จ์–ด์ง€๋Š” ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ๋‹ค.
  • ๊ทธ๋ ‡๊ธฐ ๋•Œ๋ฌธ์— Sort ๊ฐ์ฒด๋ฅผ ๋งค๊ฐœ๋ณ€์ˆ˜๋กœ ์ฃผ์–ด ๊ฐ€๋…์„ฑ์„ ๋ณด์™„ํ•˜๋Š” ๋ฐฉ๋ฒ• ๋˜ํ•œ ์žˆ๋‹ค.
List<Product> findByName(String name, Sort sort);
// Service๋‹จ์—์„œ indByName์„ ํ˜ธ์ถœํ•˜๋Š” ์˜ˆ์‹œ
productRepository.findByName("์—ฐํ•„", Sort.by(Order.asc("price")));
productRepository.findByName("๋ณผํŽœ", Sort.by(Order.asc("price"), Order.desc("stock")));
  • Sort ํด๋ž˜์Šค๋Š” ๋‚ด๋ถ€ ํด๋ž˜์Šค๋กœ ์ •์˜๋˜์–ด ์žˆ๋Š” Order ๊ฐ์ฒด๋ฅผ ํ™œ์šฉํ•ด ์ •๋ ฌ ๊ธฐ์ค€์„ ์„ธ์šฐ๊ณ , Order ๊ฐ์ฒด ๋‚ด ์žˆ๋Š” asc() ๋ฉ”์„œ๋“œ์™€ desc() ๋ฉ”์„œ๋“œ๋ฅผ ํ™œ์šฉํ•˜์—ฌ ์˜ค๋ฆ„์ฐจ์ˆœ๊ณผ ๋‚ด๋ฆผ์ฐจ์ˆœ์„ ์ง€์ •ํ•œ๋‹ค.
  • ์—ฌ๋Ÿฌ ์ •๋ ฌ ๊ธฐ์ค€์„ ์‚ฌ์šฉํ•  ๊ฒฝ์šฐ์—๋Š” ,(์ฝค๋งˆ)๋ฅผ ์ด์šฉํ•˜์—ฌ ๊ตฌ๋ถ„ํ•œ๋‹ค.
  • Sort ํด๋ž˜์Šค๋ฅผ ํ˜ธ์ถœํ•œ ์œ„์น˜์—์„œ ์ •๋ ฌ ๊ธฐ์ค€์ด ๊ธธ์–ด์ ธ ๊ฐ€๋…์„ฑ์ด ๋–จ์–ด์ง€๋Š” ๋ฌธ์ œ์ ์ด ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ๋‹ค.
  • ๊ทธ๋ ‡๊ธฐ์— ํ˜ธ์ถœํ•˜๋Š” ๋ถ€๋ถ„์—์„œ ํ•˜๋‚˜์˜ ๋ฉ”์„œ๋“œ๋กœ ๋ถ„๋ฆฌํ•ด์„œ Query method๋ฅผ ํ˜ธ์ถœํ•˜๋Š” ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•˜๋Š” ๋ฐฉ๋ฒ• ๋˜ํ•œ ์žˆ๋‹ค.
class ProductService{
...
productRepository.findByName("์—ฐํ•„", getSort());
...
private Sort getSort(){ // ํ•„์š”ํ•œ ์ฟผ๋ฆฌ๋ฉ”์„œ๋“œ๋ฅผ ํ•˜๋‚˜์˜ ๋ฉ”์„œ๋“œ๋กœ ๋ถ„๋ฆฌํ•˜์—ฌ ์ฝ”๋“œ๋ฅผ ์žฌํ™œ์šฉ ์ธ ๊ฒฌ์„ ๋†’์˜€๋‹ค.
	return Sort.by(
    	Order.Asc("price"),
        Order.Desc("stock")
    );
}

ํŽ˜์ด์ง• ์ฒ˜๋ฆฌ

ํŽ˜์ด์ง•(Paging)์ด๋ž€ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์˜ ๋ ˆ์ฝ”๋“œ๋ฅผ ๊ฐœ์ˆ˜๋กœ ๋‚˜๋ˆ  ํŽ˜์ด์ง€๋ฅผ ๊ตฌ๋ถ„ํ•˜๋Š” ๊ฒƒ์„ ์˜๋ฏธํ•œ๋‹ค. ์ด๋ฅผ ํ†ตํ•ด ๋งŽ์€ ์–‘์˜ ๋ฐ์ดํ„ฐ๋ฅผ ํšจ์œจ์ ์œผ๋กœ ์ฒ˜๋ฆฌํ•˜๊ณ , ์‚ฌ์šฉ์ž์—๊ฒŒ ํ•„์š”ํ•œ ๋ถ€๋ถ„๋งŒ์„ ๋ณด์—ฌ์ค„ ์ˆ˜ ์žˆ๋‹ค.

  • JPA์—์„œ๋Š” Page์™€ Pageable ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ํŽ˜์ด์ง•์„ ๊ตฌํ˜„ํ•œ๋‹ค.
// ํŽ˜์ด์ง• ์ฒ˜๋ฆฌ๋ฅผ ์œ„ํ•œ ์ฟผ๋ฆฌ ๋ฉ”์„œ๋“œ
Page<Product> findByName(String name, Pageable pageable);
  • return type์œผ๋กœ Page๋ฅผ ์„ค์ •ํ•˜๊ณ , parameter์—๋Š” pageable ํƒ€์ž…์˜ ๊ฐ์ฒด๋ฅผ ์ •์˜ํ•˜์˜€๋‹ค.
  • Page: ํŽ˜์ด์ง•๋œ ๊ฒฐ๊ณผ๋ฅผ ํฌํ•จํ•˜๋Š” ๊ฐ์ฒด๋กœ, ์กฐํšŒ๋œ ๋ฐ์ดํ„ฐ ๋ฆฌ์ŠคํŠธ์™€ ํ•จ๊ป˜ ํŽ˜์ด์ง€ ์ •๋ณด(์ด ํŽ˜์ด์ง€ ์ˆ˜, ํ˜„์žฌ ํŽ˜์ด์ง€ ๋ฒˆํ˜ธ, ์ด ๋ ˆ์ฝ”๋“œ ์ˆ˜ ๋“ฑ)๋ฅผ ์ œ๊ณตํ•œ๋‹ค.
  • Pageable: ํŽ˜์ด์ง• ์ •๋ณด๋ฅผ ๋‹ด๊ณ  ์žˆ๋Š” ๊ฐ์ฒด๋กœ, ํŽ˜์ด์ง€ ๋ฒˆํ˜ธ์™€ ํŽ˜์ด์ง€ ํฌ๊ธฐ ๋“ฑ์„ ์„ค์ •ํ•  ์ˆ˜ ์žˆ๋‹ค.
// Service๋‹จ์—์„œ indByName์„ ํ˜ธ์ถœํ•˜๋Š” ์˜ˆ์‹œ
Page<Product> productPage = produtRepository.findByName("์—ฐํ•„, PageRequest.of(0, 2));
for(Product product : productPage.getContent()){
	System.out.println(product);
}

// ์ถœ๋ ฅ๊ฒฐ๊ณผ์˜ˆ์‹œ
// Product{id=1, name='์—ฐํ•„', price=100.0, stock=50}
// Product{id=2, name='์—ฐํ•„', price=120.0, stock=30}
Hibernate: 
    select
        product0_.id as id1_0_,
        product0_.name as name2_0_,
        product0_.price as price3_0_,
        product0_.stock as stock4_0_
    from
        product product0_
    where
        product0_.name=? limit ?
Hibernate: 
    select
        count(product0_.id) as col_0_0_
    from
        product product0_
    where
        product0_.name=?
  • PageRequest๋Š” Pageable์˜ ๊ตฌํ˜„์ฒด์ด๋‹ค. ๋‹ค์‹œ ๋งํ•ด Pageable ๊ฐ์ฒด๋Š” PageRequest๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์ƒ์„ฑํ•œ๋‹ค.
  • limit ์ ˆ์€ ๊ฒฐ๊ณผ๋กœ ๋ฐ˜ํ™˜๋  ํ–‰(row)์˜ ์ˆ˜๋ฅผ ์ œํ•œํ•˜๋Š” ๋ฐ ์‚ฌ์šฉ๋œ๋‹ค.
  • Page ๊ฐ์ฒด์—์„œ ์ œ๊ณตํ•˜๋Š” getContent() ๋ฉ”์„œ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์—”ํ‹ฐํ‹ฐ์˜ ๋ฆฌ์ŠคํŠธ๋ฅผ ๊ฐ€์ ธ์˜ฌ ์ˆ˜ ์žˆ๋‹ค.
Pageable of() ๋ฉ”์„œ๋“œ์˜ ์ข…๋ฅ˜
of ๋ฉ”์„œ๋“œ๋งค๊ฐœ๋ณ€์ˆ˜ ์„ค๋ช…๋น„๊ณ 
of(int page, int size)ํŽ˜์ด์ง€ ๋ฒˆํ˜ธ(0๋ถ€ํ„ฐ ์‹œ์ž‘), ํŽ˜์ด์ง€๋‹น ๋ฐ์ดํ„ฐ ๊ฐฏ์ˆ˜๋ฐ์ดํ„ฐ ์ •๋ ฌX
of(int page, int size, Sort)ํŽ˜์ด์ง€ ๋ฒˆํ˜ธ(0๋ถ€ํ„ฐ ์‹œ์ž‘), ํŽ˜์ด์ง€๋‹น ๋ฐ์ดํ„ฐ ๊ฐฏ์ˆ˜, ์ •๋ ฌsort์— ์˜ํ•ด ์ •๋ ฌ
of(int page, int size, Direction, String --- ์†์„ฑ)ํŽ˜์ด์ง€ ๋ฒˆํ˜ธ(0๋ถ€ํ„ฐ ์‹œ์ž‘), ํŽ˜์ด์ง€๋‹น ๋ฐ์ดํ„ฐ ๊ฐฏ์ˆ˜, ์ •๋ ฌ ๋ฐฉํ–ฅ, ์†์„ฑ(์ปฌ๋Ÿผ)Sort.by(direction, properties)์— ์˜ํ•ด ์ •๋ ฌ

์—ฌ๊ธฐ๊นŒ์ง€ ์ž˜ ๋”ฐ๋ผ์™”์œผ๋ฉด ํ•œ๊ฐ€์ง€ ์˜๋ฌธ์ ์ด ๋“ค ๊ฒƒ์ด๋‹คโ“

๐Ÿ™‹๐Ÿปโ€โ™‚๏ธ : "OK, ๊ทธ๋Ÿผ ๊ทธ๋ƒฅ JPQL(ํ˜น์€ native SQL)์„ ์ž‘์„ฑํ•˜์ง€ ์•Š๊ณ  Query Method๋งŒ ์ž‘์„ฑํ•˜๋ฉด ๋˜๋Š”๊ฑฐ์•ผ??"
๐Ÿ“ข : "์Œ.. ๊ทธ๋ ‡๊ฒŒ๋„ ์ƒ๊ฐ ํ•  ์ˆ˜ ์žˆ์–ด ํ•˜์ง€๋งŒ ์•„๋ƒ!!"

  • ์šฐ์„  Spring Data JPA๋Š” ๋ฉ”์„œ๋“œ ์ด๋ฆ„์„ ๋ถ„์„ํ•˜์—ฌ ์ž๋™์œผ๋กœ ์ฟผ๋ฆฌ๋ฅผ ์ƒ์„ฑํ•˜๋Š” ๊ธฐ๋Šฅ์„ ์ œ๊ณตํ•˜๋ฉฐ ์ด๋ฅผ ๋ฉ”์„œ๋“œ ์ฟผ๋ฆฌ ์ƒ์„ฑ(Method Query Creation)์ด๋ผ๊ณ  ํ•œ๋‹ค!!
  • ์ด ๊ธฐ๋Šฅ์„ ํ†ตํ•ด ์šฐ๋ฆฌ๋Š” ํŠน์ • ํŒจํ„ด์„ ๋”ฐ๋ฅด๋Š” ๋ฉ”์„œ๋“œ ์ด๋ฆ„์„ ์ •์˜ํ•จ์œผ๋กœ์จ ๋ณต์žกํ•œ ์ฟผ๋ฆฌ๋ฅผ ์ž‘์„ฑํ•  ํ•„์š” ์—†์ด ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์ž‘์—…์„ ๊ฐ„ํŽธํ•˜๊ฒŒ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ๋‹ค. -> '์‰ฝ์ฃ ? ์•„ ์‰ฝ์ฃ ๋Š” ์–ด๋ ค์šด ๋ง์˜ ๋ฐ˜๋Œ€๋ง์ž…๋‹ˆ๋‹ค. ๊น”๊น”'
  • ๊ทธ๋Ÿฌ๋‚˜!! BUT!! However!! Nevertheless!!
    ๋ณต์žกํ•œ ์กฐ๊ฑด์„ ๊ฐ€์ง„ ์ฟผ๋ฆฌ๋‚˜ ์—ฌ๋Ÿฌ ํ…Œ์ด๋ธ”์„ ์กฐ์ธํ•ด์•ผ ํ•˜๋Š” ๊ฒฝ์šฐ, ํŠน์ • ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์˜ ๊ณ ์œ ํ•œ ํ•จ์ˆ˜๋‚˜ ๊ธฐ๋Šฅ์„ ์‚ฌ์šฉํ•ด์•ผ ํ•˜๋Š” ๊ฒฝ์šฐ, ์—ฌ๋Ÿฌ ์กฐ๊ฑด์„ ๋™์ ์œผ๋กœ ์ถ”๊ฐ€ํ•ด์•ผ ํ•˜๋Š” ๊ฒฝ์šฐ Query Method๋กœ ๊ตฌํ˜„ํ•˜๊ธฐ๊ฐ€ ์–ด๋ ต๋‹ค.
    => @Query ์–ด๋…ธํ…Œ์ด์…˜์„ ์‚ฌ์šฉํ•˜์—ฌ ์ง์ ‘ ์ฟผ๋ฆฌ๋ฌธ์„ ์ž‘์„ฑํ•ด์ฃผ๋ฉด ๋œ๋‹ค.
// Example
package com.example.firstobject.repository;

import com.example.firstobject.entity.Comment;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.stereotype.Repository;

import java.util.List;

@Repository
public interface CommentRepository extends JpaRepository<Comment, Long> {
    // ํŠน์ • ๊ฒŒ์‹œ๊ธ€์˜ ๋ชจ๋“  ๋Œ“๊ธ€ ์กฐํšŒ
  	@Query("SELECT p FROM Product p WHERE p.name = :name")
    List<Product> findByName(@Param("name") String name);
    // ํŠน์ • ๋‹‰๋„ค์ž„์˜ ๋ชจ๋“  ๋Œ“๊ธ€ ์กฐํšŒ
    List<Comment> findByNickname(String nickname);
}
  • ์ด๋Ÿฌํ•œ ๊ฐ„ํŽธํ•œ ๊ธฐ๋Šฅ ๋•๋ถ„์— ๋ฉ”์„œ๋“œ ์ด๋ฆ„๋งŒ์œผ๋กœ ๊ฐ„๋‹จํ•œ ์ฟผ๋ฆฌ๋ฅผ ์ƒ์„ฑํ•  ์ˆ˜ ์žˆ๋„ ์žˆ๊ณ  ํ•„์š”์— ๋”ฐ๋ผ ์ง์ ‘ ์ฟผ๋ฆฌ๋ฅผ ์ž‘์„ฑํ•˜์—ฌ ๋ณต์žกํ•œ ์š”๊ตฌ ์‚ฌํ•ญ์„ ์ถฉ์กฑํ•  ์ˆ˜ ์žˆ๋‹ค.

@Query annotation

@Query ์–ด๋…ธํ…Œ์ด์…˜์€ JPQL ๋˜๋Š” ๋„ค์ดํ‹ฐ๋ธŒ SQL์„ ์ง์ ‘ ์ž‘์„ฑํ•˜์—ฌ ํŠœ๋‹๋œ ์ฟผ๋ฆฌ๋ฅผ ์‚ฌ์šฉํ•  ๋•Œ ์‚ฌ์šฉํ•˜๋Š” ์–ด๋…ธํ…Œ์ด์…˜์ด๋‹ค.

  • ๊ธฐ๋ณธ์ ์œผ๋กœ Spring Data JPA๋Š” ๋ฉ”์„œ๋“œ ์ด๋ฆ„์„ ๊ธฐ๋ฐ˜์œผ๋กœ JPQL์„ ์ž๋™์œผ๋กœ ์ƒ์„ฑํ•œ๋‹ค. ํ•˜์ง€๋งŒ ๊ฐœ๋ฐœ์ž๊ฐ€ ์ง์ ‘ ์ž‘์„ฑํ•œ JPQL ๋˜๋Š” ๋„ค์ดํ‹ฐ๋ธŒ SQL์„ ์‚ฌ์šฉํ•˜๊ณ  ์‹ถ๋‹ค๋ฉด @Query ์–ด๋…ธํ…Œ์ด์…˜์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.
public interface ProductRepository extends JpaRepository<Product, Long> {

    // @Query ์–ด๋…ธํ…Œ์ด์…˜์„ ์‚ฌ์šฉํ•œ ์‚ฌ์šฉ์ž ์ •์˜ JPQL ์ฟผ๋ฆฌ
    @Query("SELECT p FROM Product p WHERE p.name = :name")
    List<Product> findByNameCustom(@Param("name") String name);

    // @Query ์–ด๋…ธํ…Œ์ด์…˜์„ ์‚ฌ์šฉํ•œ ๋„ค์ดํ‹ฐ๋ธŒ SQL ์ฟผ๋ฆฌ
    @Query(value = "SELECT * FROM product WHERE name = :name", nativeQuery = true)
    List<Product> findByNameNative(@Param("name") String name);
}

native SQL VS JPQL

native SQLJPQL
๋Œ€์ƒ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ํ…Œ์ด๋ธ”์—”ํ‹ฐํ‹ฐ ๊ฐ์ฒด
๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ๋…๋ฆฝ์„ฑ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์ข…์†์ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ๋…๋ฆฝ์ 
๊ตฌ๋ฌธSQL ๊ตฌ๋ฌธ ์ง์ ‘ ์‚ฌ์šฉ๊ฐ์ฒด ์ง€ํ–ฅ์ ์ธ ๊ตฌ๋ฌธ
์œ ์—ฐ์„ฑ ๋ฐ ์ตœ์ ํ™”๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์˜ ๊ณ ์œ  ๊ธฐ๋Šฅ ์‚ฌ์šฉ๊ฐ์ฒด ์ง€ํ–ฅ์ ์ธ ์ ‘๊ทผ ๋ฐฉ์‹
  • JPQL์€ FROM ์ ˆ ๋’ค์— ์—”ํ‹ฐํ‹ฐ ํƒ€์ž…์„ ์ง€์ •ํ•˜๊ณ  ๋ณ„์นญ์„ ์„ค์ •ํ•œ๋‹ค.
  • WHERE ์ ˆ์„ ํ†ตํ•ด SQL๊ณผ ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ ์กฐ๊ฑด์„ ์ง€์ •ํ•˜๋Š”๋ฐ ?1, ?2์™€ ๊ฐ™์ด ์ˆœ๋ฒˆ์„ ์ด์šฉํ•ด์„œ ์ธ์ž๋ฅผ ๋ฐ›์•„์˜ฌ ์ˆ˜๋„ ์žˆ๋‹ค.
// ์ˆœ๋ฒˆ์„ ์ด์šฉํ•ด์„œ ์ธ์ž๋ฅผ ๋ฐ›์•„ ์˜ฌ ์ˆ˜ ์žˆ๋Š” Example
@Query("SELECT p FROM Product p WHERE p.name = ?1")
List<Product> findByName(String name);
  • ํ•˜์ง€๋งŒ ํŒŒ๋ผ๋ฏธํ„ฐ์˜ ์ˆœ์„œ๊ฐ€ ๋ฐ”๋€” ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์— @Param์„ ์–ด๋…ธํ…Œ์ด์…˜์„ ์‚ฌ์šฉํ•˜์—ฌ ํŒŒ๋ผ๋ฏธํ„ฐ๋ฅผ ์ง์ ‘ ๋ฐ”์ธ๋”ฉํ•˜๋Š” ๋ฐฉ์‹์œผ๋กœ ๋ฉ”์†Œ๋“œ๋ฅผ ๊ตฌํ˜„ํ•˜๋ฉด ์˜ค๋ฅ˜ ๋ฐœ์ƒ ํ™•๋ฅ ์„ ์ค„์ด๊ณ  ์œ ์ง€๋ณด์ˆ˜๋ฅผ ์ˆ˜์›”ํ•˜๊ฒŒ ํ•  ์ˆ˜ ์žˆ๋‹ค.
  • ๋งˆ์ง€๋ง‰์œผ๋กœ, @Query ์–ด๋…ธํ…Œ์ด์…˜์€ ์—”ํ‹ฐํ‹ฐ ํƒ€์ž…์ด ์•„๋‹ˆ๋ผ ์›ํ•˜๋Š” ์ปฌ๋Ÿผ์˜ ๊ฐ’๋งŒ ์ถ”์ถœํ•  ์ˆ˜๋„ ์žˆ๊ณ  ์ด๋•Œ์˜ ๋ฆฌํ„ด ํƒ€์ž…์€ List<Object[]>ํ˜•ํƒœ๋กœ ์ง€์ •ํ•  ์ˆ˜ ์žˆ๋‹ค.

์šฉ์–ด ์ •๋ฆฌ๐Ÿคท๐Ÿปโ€โ™‚๏ธ

  • ์Šคํ”„๋ง ํ•˜์œ„ ํ”„๋กœ์ ํŠธ : Spring ํ”„๋ ˆ์ž„์›Œํฌ์˜ ๊ธฐ๋Šฅ์„ ํ™•์žฅํ•˜๊ณ  ํŠน์ • ์šฉ๋„๋ฅผ ์œ„ํ•ด ๋” ์‰ฝ๊ฒŒ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋„๋ก ์ œ๊ณตํ•˜๋Š” ์ถ”๊ฐ€ ๋ชจ๋“ˆ ๋˜๋Š” ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์ด๋‹ค.
  • ์—”ํ‹ฐํ‹ฐ ๋งค๋‹ˆ์ € : JPA(Java Persistence API)์—์„œ ์ค‘์š”ํ•œ ์—ญํ• ์„ ํ•˜๋Š” ์ธํ„ฐํŽ˜์ด์Šค๋กœ, ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์ด ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์™€ ์ƒํ˜ธ ์ž‘์šฉํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•˜๋Š” ์ฃผ์š” ๊ฐ์ฒด์ด๋‹ค. ์—”ํ‹ฐํ‹ฐ์˜ ์ƒ๋ช… ์ฃผ๊ธฐ๋ฅผ ๊ด€๋ฆฌํ•˜๊ณ , ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์ฟผ๋ฆฌ๋ฅผ ์ˆ˜ํ–‰ํ•˜๋ฉฐ, ํŠธ๋žœ์žญ์…˜์„ ๊ด€๋ฆฌํ•œ๋‹ค.

Reference๐Ÿ“š

  • ์Šคํ”„๋ง๋ถ€ํŠธ ํ•ต์‹ฌ ๊ฐ€์ด๋“œ - ์žฅ์ •์šฐ -
profile
์ฒœ์ฒœํžˆ, ๊พธ์ค€ํžˆ, ๊ทธ๋ฆฌ๊ณ  ๋๊นŒ์ง€

2๊ฐœ์˜ ๋Œ“๊ธ€

comment-user-thumbnail
2024๋…„ 6์›” 23์ผ

Dohyeon Kong ๊ทธ๋Š” JPA ์‹ ์ธ๊ฐ€?! Dohyeon Kong ๊ทธ๋Š” JPA ์‹ ์ธ๊ฐ€?! Dohyeon Kong ๊ทธ๋Š” JPA ์‹ ์ธ๊ฐ€?! Dohyeon Kong ๊ทธ๋Š” JPA ์‹ ์ธ๊ฐ€?! Dohyeon Kong ๊ทธ๋Š” JPA ์‹ ์ธ๊ฐ€?! Dohyeon Kong ๊ทธ๋Š” JPA ์‹ ์ธ๊ฐ€?! Dohyeon Kong ๊ทธ๋Š” JPA ์‹ ์ธ๊ฐ€?! Dohyeon Kong ๊ทธ๋Š” JPA ์‹ ์ธ๊ฐ€?! Dohyeon Kong ๊ทธ๋Š” JPA ์‹ ์ธ๊ฐ€?! Dohyeon Kong ๊ทธ๋Š” JPA ์‹ ์ธ๊ฐ€?!

1๊ฐœ์˜ ๋‹ต๊ธ€