๐ŸŒผ Spring ์‹ฌํ™” โ‘ข - JPQL ๊ธฐ์ดˆ, fetch join

ํ•˜๋ฆฌ๋น„ยท2025๋…„ 5์›” 13์ผ
0

๐ŸŒผ Spring

๋ชฉ๋ก ๋ณด๊ธฐ
9/11

๐Ÿ“˜ JPQL

  • ํŠน์ง•
    - ๋Œ€์ƒ์€ ๊ฐ์ฒด (ํ…Œ์ด๋ธ”์ด ์•„๋‹˜)
    - ์˜์†์„ฑ ์ปจํƒ์ŠคํŠธ ํ™œ์šฉ ๊ฐ€๋Šฅ
    - ์ปดํŒŒ์ผ ์‹œ์ ์— ์—”ํ‹ฐํ‹ฐ-ํ•„๋“œํƒ€์ž… ํ™•์ธ ํ›„ ์˜ค๋ฅ˜ ๊ฐ์†Œ

๐Ÿ“– JPQL ๋ฌธ๋ฒ•

๐Ÿ“Œ ๊ฒฐ๊ณผ ์กฐํšŒ

โ–ถ๏ธ ํƒ€์ž… ์ •ํ•˜๊ธฐ

โถ TypeQuery

  • ํƒ€์ž…์ด ๋ช…ํ™•ํ• ๋•Œ ! (์ฃผ๋กœ ์—”ํ‹ฐํ‹ฐ๋‚˜ ํŠน์ • ํƒ€์ž…์ด ์žˆ์„๋•Œ)
  • ์ฃผ๋กœ ์‚ฌ์šฉํ•œ๋‹ค!
TypedQuery<Tutor> typeQuery1 = em.createQuery("select t from Tutor t", Tutor.class);
TypedQuery<String> typeQuery2 = em.createQuery("select t.name from Tutor t", String.class);

โทQuery

  • ๋ฐ˜ํ™˜ ํƒ€์ž… ๋ช…ํ™•ํ•˜์ง€ ์•Š์„๋•Œ ( = ๋‹ค์–‘ํ•œ ํƒ€์ž…์˜ ๋ฐ์ดํ„ฐ ๋ฐ˜ํ™˜)
  • Object๋กœ ๋ฐ˜ํ™˜ํ•˜๋ฏ€๋กœ ํ˜•๋ณ€ํ™˜ ํ•„์š”ํ•  ์ˆ˜๋„
Query query = em.createQuery("select t.name, t.age from Tutor t");

โ–ถ๏ธ ๊ฒฐ๊ณผ ์กฐํšŒ

โถ getResultList()

  • ๊ฒฐ๊ณผ๊ฐ€ ํ•˜๋‚˜ ์ด์ƒ์ผ ๋•Œ ์‚ฌ์šฉํ•œ๋‹ค.
  • List ๋ฐ˜ํ™˜ (๊ฒฐ๊ณผ๊ฐ€ ์—†๋‹ค๋ฉด ๋นˆ List ๋ฐ˜ํ™˜)
List resultList = em.createQuery("select t from Tutor t").getResultList();

โท getSingleResult()

  • ๊ฒฐ๊ณผ๊ฐ€ ๋”ฑ ํ•˜๋‚˜์ผ๋•Œ
  • ์ฟผ๋ฆฌ ๋’ค์— ์—”ํ‹ฐํ‹ฐ ํด๋ž˜์Šค๋ฅผ ๋ช…์‹œํ•ด์ค€๋‹ค (๋ฐ˜ํ™˜ํƒ€์ž…)
Tutor singleResult = em.createQuery("select t from Tutor t where t.id = 1L", Tutor.class).getSingleResult();

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

๋™์ ์œผ๋กœ ๊ฐ’์„ ์ „๋‹ฌํ•œ๋‹ค, ์ฟผ๋ฆฌ ์žฌ์‚ฌ์šฉ ๊ฐ€๋Šฅ

Tutor wonuk = em.createQuery("select t from Tutor t where t.name = โœ…:name", Tutor.class)
                    .setParameter("name", "wonuk")โœ…ํŒŒ๋ผ๋ฏธํ„ฐ ์ง€์ •
                    .getSingleResult();
System.out.println("wonuk.getName() = " + wonuk.getName());
System.out.println("wonuk.getAge() = " + wonuk.getAge());

๐Ÿ“Œ @Embedded / @Embeddedable

โ–ถ๏ธ JPA์—์„œ ์—ฌ๋Ÿฌ ํ•„๋“œ๋ฅผ ํ•˜๋‚˜์˜ ๊ฐ’ ๊ฐ์ฒด๋กœ ๋ฌถ์–ด ์‚ฌ์šฉํ•˜๋Š” ์–ด๋…ธํ…Œ์ด์…˜

โœ…@Embeddable - ๊ฐ’์„ ์ •์˜ํ•˜๋Š” ์ชฝ. ๋‚ด์žฅ๋  ํด๋ž˜์Šค (์˜ˆ: Period, Address)
โœ… @Embedded - ๊ฐ’์„ ์‚ฌ์šฉํ•˜๋Š” ์ชฝ. ์—”ํ‹ฐํ‹ฐ์— ํฌํ•จ์‹œํ‚ค๋Š” ํ•„๋“œ (์˜ˆ: Tutor.period)

โ–ถ๏ธ ์ƒํ™ฉ ์˜ˆ์‹œ

์ƒํ™ฉ์„ค๋ช…
๊ฐ’๋“ค์„ ํ•œ ๋ฉ์–ด๋ฆฌ๋กœ ํ‘œํ˜„ํ•˜๊ณ  ์‹ถ์„ ๋•Œ๊ธฐ๊ฐ„(์‹œ์ž‘~์ข…๋ฃŒ), ์ฃผ์†Œ(์‹œ/๋„/์šฐํŽธ๋ฒˆํ˜ธ), ์ด๋ฆ„(์„ฑ/์ด๋ฆ„) ๋“ฑ
์—ฌ๋Ÿฌ ์—”ํ‹ฐํ‹ฐ์—์„œ ์ค‘๋ณต๋œ ๊ฐ’ ๊ตฌ์กฐ๊ฐ€ ๋‚˜์˜ฌ ๋•Œ์˜ˆ: Period๋ฅผ Tutor, Employee์—์„œ ํ•จ๊ป˜ ์“ฐ๊ณ  ์‹ถ์„ ๋•Œ
๊ฐ’ ์ž์ฒด์˜ ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง์„ ํฌํ•จํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•˜๊ณ  ์‹ถ์„ ๋•ŒPeriod.isWork(Date) ์ฒ˜๋Ÿผ ํ•ด๋‹น ๊ฐ’๋งŒ์˜ ๋ฉ”์„œ๋“œ ๋งŒ๋“ค ์ˆ˜ ์žˆ์Œ

โถ @Embedded ์‚ฌ์šฉ

@Entity
public class Tutor {
		
		@Id
		@GeneratedValue
		private Long id;
		
		private String name;
		
		@Embedded // โœ… Embedded ์‚ฌ์šฉ
		private Period period;

}

โท @Embeddable ์‚ฌ์šฉ

@Embeddable// โœ… Embedded ์ •์˜
public class Period {
 
  @Temporal(TemporalType.DATE) <--- โœ… ๋‚ ์งœ ๋งคํ•‘์— ์‚ฌ์šฉ
  Date startDate;
 
  @Temporal(TemporalType.Date)
  Date endDate;
 
  public boolean isWork (Date date) { <--- โœ… ์ž์ฒด ๊ฒ€์ฆ ๋กœ์ง
	    // startDate <= date <= endDate ํ™•์ธ
      return (startDate == null || !date.before(startDate)) &&
             (endDate == null || !date.after(endDate));
  }
}

โธ ๋ฐ์ดํ„ฐ ์กฐํšŒ

idnamestart_dateend_date
  • tutor ํ…Œ์ด๋ธ”์— period ๊ฐ€ ์•„๋‹Œ,
    period ๋‚ด ํ•„๋“œ์ธ startDate, endDate๊ฐ€ ๋‚˜์˜จ๋‹ค

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

โ–ถ๏ธ ์ฟผ๋ฆฌ์—์„œ ์–ด๋–ค ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์˜ฌ ์ง€ ์„ ํƒํ•˜๋Š” ๊ฒƒ ( select ์–ด๋–ค๊ฑฐ ํ• ์ง€? )

โ–ถ๏ธ ์™œ ์‚ฌ์šฉํ•˜๋Š”๊ฐ€?

  • ๋ชจ๋“  ๋ฐ์ดํ„ฐ๋ฅผ ๋‹ค ๊ฐ€์ ธ์˜ค๋Š” ๊ฑด ๋น„ํšจ์œจ์ 
  • ํ•„์š”ํ•œ ํ•„๋“œ๋งŒ ์กฐํšŒํ•˜๋ฉด ์„ฑ๋Šฅ ์ตœ์ ํ™” ๊ฐ€๋Šฅ
  • ๋„คํŠธ์›Œํฌ ๋น„์šฉ ์ ˆ๊ฐ, ์กฐํšŒ ์†๋„ ํ–ฅ์ƒ

โถ Entity ํ”„๋กœ์ ์…˜

  • ์—”ํ‹ฐํ‹ฐ ์ „์ฒด๋ฅผ ํ†ต์งธ๋กœ ์กฐํšŒํ•˜๋Š” ๋ฐฉ์‹
  • ์กฐํšŒ๋œ ๊ฐ์ฒด๋Š” ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ์— ์˜ํ•ด ๊ด€๋ฆฌ๋œ๋‹ค (Dirty Checking ๊ฐ€๋Šฅ)
Tutor tutor = new Tutor("wonuk", 100);
em.persist(tutor);

// ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ ์ดˆ๊ธฐํ™” โ†’ ์กฐํšŒํ•œ tutor๋Š” ๋” ์ด์ƒ ๊ด€๋ฆฌ๋˜์ง€ ์•Š์Œ
em.flush();
em.clear();

// Tutor ์—”ํ‹ฐํ‹ฐ ์ „์ฒด ์กฐํšŒ
List<Tutor> tutorList = em.createQuery("select t from Tutor t", Tutor.class).getResultList();
Tutor wonuk = tutorList.get(0);

// ์—”ํ‹ฐํ‹ฐ๊ฐ€ ๋‹ค์‹œ ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ์— ๋“ค์–ด์™€์„œ ๋ณ€๊ฒฝ ๊ฐ์ง€ ๊ฐ€๋Šฅ
wonuk.setName("wonuk2");
  • ๐Ÿงท ์—ฐ๊ด€ ์—”ํ‹ฐํ‹ฐ ์กฐํšŒ: ๋ฌต์‹œ์  vs ๋ช…์‹œ์  JOIN
    // ๋ฌต์‹œ์  JOIN โ†’ JPQL์—์„œ๋Š” ์ž‘์„ฑํ•˜์ง€ ์•Š์•˜์ง€๋งŒ ๋‚ด๋ถ€์ ์œผ๋กœ JOIN ๋ฐœ์ƒ
    Company company = em.createQuery(
        "select t.company from Tutor t", Company.class
    ).getSingleResult();
    
    // ๋ช…์‹œ์  JOIN โ†’ ์ฟผ๋ฆฌ์—์„œ JOIN์„ ๋ช…ํ™•ํžˆ ์„ ์–ธ
    Company companyV2 = em.createQuery(
        "select t from Tutor t join t.company", Company.class
    ).getSingleResult();
    • ๐Ÿ’ก ๋ฌต์‹œ์  JOIN์€ SQL์„ ์˜ˆ์ธกํ•˜๊ธฐ ์–ด๋ ค์›Œ ์œ„ํ—˜ํ•จ
      โ†’ ๋ช…์‹œ์ ์œผ๋กœ JOIN์„ ์„ ์–ธํ•˜๋Š” ๊ฒƒ์ด ์ข‹๋‹ค.

โท Embedded ํ”„๋กœ์ ์…˜

List<Period> periods = em.createQuery(
	"select t.period from Tutor t", Period.class).getResultList();

* `select p from Period p` โ†’ โŒ ๋ถˆ๊ฐ€๋Šฅ
* Embedded ๊ฐ์ฒด๋Š” ๋…๋ฆฝ์ ์ธ ์—”ํ‹ฐํ‹ฐ๊ฐ€ ์•„๋‹ˆ๊ธฐ ๋•Œ๋ฌธ

โœ”๏ธ ์กฐ๊ฑด ๊ฒ€์ƒ‰ ์˜ˆ์‹œ

// Embedded ๋‚ด๋ถ€ ํ•„๋“œ ์ ‘๊ทผ ๊ฐ€๋Šฅ
"select t from Tutor t where t.period.startDate < :today"

โœ”๏ธ ์ƒ์† ๊ตฌ์กฐ โ†’ ์ง๊ด€์ 

"select t from Tutor t where t.startDate < :today"
// โ†’ ์ด๊ฑด period ์—†์ด ๋ฐ”๋กœ ์ ‘๊ทผ ๊ฐ€๋Šฅ (MappedSuperclass์˜ ๊ฒฝ์šฐ)

โธ Scalar ํ”„๋กœ์ ์…˜

  • ์—”ํ‹ฐํ‹ฐ๊ฐ€ ์•„๋‹Œ ๋‹จ์ผ ํ•„๋“œ(๋ฌธ์ž์—ด, ์ˆซ์ž ๋“ฑ) ๋˜๋Š” ์—ฌ๋Ÿฌ ํ•„๋“œ๋งŒ ์กฐํšŒํ•  ๋•Œ
List<Object[]> resultList = em.createQuery(
    "select t.name, t.age from Tutor t"
).getResultList();

Object[] result = resultList.get(0);
System.out.println("์ด๋ฆ„: " + result[0]);  // name
System.out.println("๋‚˜์ด: " + result[1]);  // age

๐Ÿ“Œ ๊ฒฐ๊ณผ๋Š” Object[] ๋ฐฐ์—ด๋กœ ๋ฆฌํ„ด๋˜๋ฏ€๋กœ, ํ˜•๋ณ€ํ™˜ ํ•„์š”

  • ๐Ÿ’ก ํ™•์žฅ โ†’ DTO ํ”„๋กœ์ ์…˜
    // DTO์— ์ƒ์„ฑ์ž ํ•„์š”: public TutorDto(String name, int age)
    List<TutorDto> dtos = em.createQuery(
       "select new com.example.TutorDto(t.name, t.age) from Tutor t", TutorDto.class ).getResultList();

    Scalar ํ”„๋กœ์ ์…˜์„ ๋” ๋ช…ํ™•ํ•˜๊ฒŒ ์‚ฌ์šฉํ•˜๊ณ  ์‹ถ๋‹ค๋ฉด DTO์— ์ง์ ‘ ๋งคํ•‘ํ•˜๋Š” ๋ฐฉ๋ฒ•์ด ๊ฐ€์žฅ ๊น”๋”ํ•˜๊ณ  ์•ˆ์ „


๐Ÿ“Œ ํŽ˜์ด์ง•(Paging)

โ–ถ๏ธ JPQL์€ ๊ธฐ๋ณธ์ ์œผ๋กœ LIMIT, OFFSET ๊ฐ™์€ SQL ๋ฌธ๋ฒ•์„ ์ง์ ‘ ์“ฐ์ง€ ์•Š๊ณ 
JPA๊ฐ€ ์ œ๊ณตํ•˜๋Š” ๋ฉ”์„œ๋“œ๋กœ ํŽ˜์ด์ง• ์ฒ˜๋ฆฌ๋ฅผ ํ•œ๋‹ค.

โ–ถ๏ธ ์‚ฌ์šฉ ๋ฉ”์„œ๋“œ

๋ฉ”์„œ๋“œ์„ค๋ช…
setFirstResult(int)์กฐํšŒ ์‹œ์ž‘ ์œ„์น˜ (OFFSET)
setMaxResults(int)๊ฐ€์ ธ์˜ฌ ๋ฐ์ดํ„ฐ ๊ฐœ์ˆ˜ (LIMIT)

List<Tutor> tutorList = em.createQuery(
  "select t from Tutor t order by t.age desc", Tutor.class
)
.setFirstResult(5)     // 6๋ฒˆ์งธ ๋ฐ์ดํ„ฐ๋ถ€ํ„ฐ ์กฐํšŒ (OFFSET = 5)
.setMaxResults(10)     // ์ด 10๊ฐœ ์กฐํšŒ (LIMIT = 10)
.getResultList();

for (Tutor tutor : tutorList) {
  System.out.println("tutor = " + tutor.getId() + ", " + tutor.getName() + ", " + tutor.getAge());
}
  • order by t.age desc
    โ†’ ๋‚˜์ด ์ˆœ์„œ๋Œ€๋กœ ๋‚ด๋ฆผ์ฐจ์ˆœ ์ •๋ ฌ (๊ฐ€์žฅ ๋‚˜์ด ๋งŽ์€ ํŠœํ„ฐ๋ถ€ํ„ฐ)
  • setFirstResult(5)
    โ†’ 6๋ฒˆ์งธ ๋ฐ์ดํ„ฐ๋ถ€ํ„ฐ ์‹œ์ž‘
  • setMaxResults(10)
    โ†’ 10๊ฐœ ๋ฐ์ดํ„ฐ๋งŒ ์กฐํšŒ


๐Ÿ“˜ fetch join

JPA์—์„œ์˜ N+1 ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•œ๋‹ค


๐Ÿ“– fetch join ์‚ฌ์šฉ๋ฒ•

๐Ÿ“Œ Entity fetch join (N:1, 1:1)

โ–ถ๏ธ ์ง€์—ฐ๋กœ๋”ฉ(LAZY) ์„ค์ •๋œ ์—ฐ๊ด€ ์—”ํ‹ฐํ‹ฐ๋ฅผ JOIN๊ณผ ๋™์‹œ์— ํ•œ ๋ฒˆ์— ๊ฐ€์ ธ์˜ค๋Š” ๋ฐฉ๋ฒ•

String query = "select t from Tutor t join fetch t.company";

โถ Tutor๊ฐ€ Company๋ฅผ ์ฐธ์กฐํ•˜๊ณ  ์žˆ๊ณ ,
โท t.getCompany().getName() ๋กœ ์ ‘๊ทผํ•˜๋ฉด ์›๋ž˜๋Š” ์ฟผ๋ฆฌ ๋˜ ๋‚ ์•„๊ฐ€์•ผํ•˜๋Š”๋ฐ
โธ fetch join์„ ์“ฐ๋ฉด ๊ทธ ์ „์— ๋ฏธ๋ฆฌ Company๊นŒ์ง€ ๊ฐ™์ด ๊ฐ€์ ธ์˜จ๋‹ค
โ†’ ์ฟผ๋ฆฌ ํ•œ ๋ฒˆ์œผ๋กœ ๋‘˜ ๋‹ค ๊ฐ€์ ธ์˜ค๋‹ˆ๊นŒ N+1 ๋ฌธ์ œ ํ•ด๊ฒฐ!

  • โœ… ์žฅ์ : ๊น”๋”ํ•˜๊ฒŒ ํ•œ ๋ฒˆ์— ๊ฐ€์ ธ์™€์„œ ์„ฑ๋Šฅ ์ข‹์Œ
  • โš ๏ธ ์ฃผ์˜: ๋ฌด์กฐ๊ฑด ๋‹ค ๋“ค๊ณ ์˜ค๋‹ˆ๊นŒ ํ•„์š” ์—†์„ ๋• ์˜คํžˆ๋ ค ๊ณผํ•˜๊ฒŒ ๊ฐ€์ ธ์˜ฌ ์ˆ˜๋„

๐Ÿ“Œ Collection fetch join

โ–ถ๏ธ ํ•œ ์—”ํ‹ฐํ‹ฐ๊ฐ€ ์—ฌ๋Ÿฌ ๊ฐœ๋ฅผ ๊ฐ–๊ณ  ์žˆ๋Š” ์ปฌ๋ ‰์…˜(์˜ˆ: ํšŒ์‚ฌ โ†’ ํŠœํ„ฐ ๋ชฉ๋ก)์„ ํ•œ ๋ฒˆ์— ๊ฐ€์ ธ์˜ค๋Š” ๋ฐฉ์‹

String query = "select c from Company c join fetch c.tutorList";

โถ Company ํ•˜๋‚˜์— Tutor ์—ฌ๋Ÿฌ ๋ช… ๋ถ™์–ด์žˆ์œผ๋ฉด,
โท SQL์€ Tutor ์ˆ˜๋งŒํผ Company๊ฐ€ ์ค‘๋ณต๋ผ์„œ ๋‚˜์˜จ๋‹ค
โ†’ ๊ทผ๋ฐ JPA๋Š” ์•Œ์•„์„œ ๊ฐ™์€ Company๋Š” ํ•œ ๋ฒˆ๋งŒ ๋งŒ๋“ค์–ด์ค€๋‹ค!

  • โœ… ์žฅ์ : N+1 ๋ฌธ์ œ ์—†์ด Company์™€ Tutor๋ฅผ ํ•œ ๋ฒˆ์— ๋‹ค ๊ฐ€์ ธ์˜ด
  • โš ๏ธ ๋‹จ์ : ํŽ˜์ด์ง•(setFirstResult, setMaxResults) ์•ˆ ๋จ
    โ†’ ์ „๋ถ€ ๋‹ค ๋ถˆ๋Ÿฌ์˜จ ๋‹ค์Œ ์ž๋ฐ” ๋ฉ”๋ชจ๋ฆฌ์—์„œ ์ž˜๋ผ๋ฒ„๋ฆผ (๋ฐ์ดํ„ฐ ๋งŽ์œผ๋ฉด ์œ„ํ—˜)

๐Ÿ“Œ @BatchSize

โ–ถ๏ธ ์ง€์—ฐ๋กœ๋”ฉ์€ ์œ ์ง€ํ•˜๋ฉด์„œ, ํ•œ ๋ฒˆ์— ์—ฌ๋Ÿฌ ๊ฐœ๋ฅผ IN ์ฟผ๋ฆฌ๋กœ ๊ฐ€์ ธ์˜ค๋Š” ๋ฐฉ์‹

@BatchSize(size = 100)
@OneToMany(mappedBy = "company")
private List<Tutor> tutorList;

โถ ์˜ˆ๋ฅผ ๋“ค์–ด Company 2๊ฐœ๊ฐ€ ์žˆ์„ ๋•Œ,
โท ๊ฐ Company์˜ tutorList๋ฅผ ์กฐํšŒํ•˜๋ ค๊ณ  ํ•˜๋ฉด
โธ Tutor๋ฅผ ํ•˜๋‚˜์”ฉ ์ฟผ๋ฆฌํ•˜๋Š” ๊ฒŒ ์•„๋‹ˆ๋ผ
โ†’ Tutor WHERE company_id IN (1, 2) ์ด๋Ÿฐ ์ฟผ๋ฆฌ๋กœ ํ•œ ๋ฒˆ์—!

โœ… ์žฅ์ : ํŽ˜์ด์ง• ๊ฐ€๋Šฅ! ์ฟผ๋ฆฌ๋„ ์ค„์–ด๋“ฆ
โš ๏ธ ์ฃผ์˜: ํ•œ ๋ฒˆ์— ๋„ˆ๋ฌด ๋งŽ์ด ๋กœ๋”ฉํ•˜๋ฉด ๋ฉ”๋ชจ๋ฆฌ ํ„ฐ์งˆ ์ˆ˜๋„ ์žˆ์œผ๋‹ˆ size ์กฐ์ ˆ ์ค‘์š”



๐ŸŒŸ JPQL ์‹ค์Šต ์ฝ”๋“œ

- ์ฟผ๋ฆฌ ์˜ˆ์‹œ

โถ Repository์˜ ํŠœํ„ฐ๋ณ„ ํ•™์ƒ ์ˆ˜ ๋ฉ”์„œ๋“œ

public interface TutorRepository extends JpaRepository<Tutor, Long> {

    @Query("select new com.example.springjpql.dto.TutorStudentCountDto(t.name, count(s)) " +
            "from Tutor t join t.students s group by t.name")
    List<TutorStudentCountDto> findTutorStudentCounts();
}

โท Repository์˜ ํ•™์ƒ ์กฐ๊ฑด๋ถ€ ๊ฒ€์ƒ‰ ๋ฉ”์„œ๋“œ

@Query("select new com.example.springjpql.dto.StudentDto(s.name, s.age) " +
        "from Student s where s.name like %:keyword% " +
        "and s.age >= :minAge and s.age <= :maxAge")
List<StudentDto> findByNameContainingAndAgeBetween(
        @Param("keyword") String keyword,
        @Param("minAge") int minAge,
        @Param("maxAge") int maxAge
);

- ํ…Œ์ŠคํŠธ ๋ฐ์ดํ„ฐ ์ถ”๊ฐ€ํ•˜๊ธฐ

โถ ํ”„๋กœํ•„ ์„ค์ •ํ•˜๊ธฐ ( application.yml )

profiles:
  active: dev โœ…

โท ํ…Œ์ŠคํŠธ์šฉ ๋ฐ์ดํ„ฐ ์ถ”๊ฐ€ ( config ํŒจํ‚ค์ง€ )

  • @PostConstruct ๋กœ Application ์ตœ์ดˆ ์‹คํ–‰ ์‹œ์—๋งŒ ์ดˆ๊ธฐํ™” ํ•˜๋„๋ก ์„ค์ •
  • @Profile("dev") dev ํ”„๋กœํ•„์—์„œ๋งŒ ๋™์ž‘ํ•˜๋„๋ก ์„ค์ •
@Slf4j
@Component
@Profile("dev") โœ…
public class DataInitializer {

    @Autowired
    private TutorRepository tutorRepository;

    @Autowired
    private StudentRepository studentRepository;

    @PostConstruct โœ…
    public void init() {
        // Tutor ๋ฐ์ดํ„ฐ ์ดˆ๊ธฐํ™”
        Tutor tutor1 = new Tutor("tutor1");
        Tutor tutor2 = new Tutor("tutor2");
        Tutor tutor3 = new Tutor("tutor3");

        tutorRepository.save(tutor1);
        tutorRepository.save(tutor2);
        tutorRepository.save(tutor3);

        // Student ๋ฐ์ดํ„ฐ ์ดˆ๊ธฐํ™”
        for (int i = 0; i < 30; i++) {
            Student student = new Student("student" + i, 20 + i);
            // ํŠœํ„ฐ๋ฅผ ์ˆœ์ฐจ์ ์œผ๋กœ ํ• ๋‹น
            if (i % 3 == 0) {
                student.setTutor(tutor1);
            } else if (i % 3 == 1) {
                student.setTutor(tutor2);
            } else {
                student.setTutor(tutor3);
            }
            studentRepository.save(student);
        }
        log.info("===== Test Data Initialized =====");
    }
}

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