JiwonDev

JPA 10 # ๊ฐ์ฒด ์ฟผ๋ฆฌ ์–ธ์–ด, JPQL

by JiwonDev

๊ฐ„๋‹จํ•œ CRUD๋Š” JPA ๋ฉ”์„œ๋“œ๋กœ ์ถฉ๋ถ„ํžˆ ๋Œ€์ฒด ๊ฐ€๋Šฅํ–ˆ๋‹ค.

ํ•˜์ง€๋งŒ SQL๋ฌธ์€ ๋น„์ฆˆ๋‹ˆ์Šค์˜ ๊ตฌ์กฐ์— ๋”ฐ๋ผ ์กฐ๊ฑด์ด ๋ณต์žกํ• ์ˆ˜๋„ ์žˆ๊ณ , ์„ฑ๋Šฅ ๊ฐœ์„ ์ด ํ•„์š”ํ•  ์ˆ˜ ์žˆ๋‹ค.

์ด๋ฅผ ์œ„ํ•ด์„œ JPA ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ์— ๋ชจ๋“  ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์˜ค๋Š”๊ฑด ์‚ฌ์‹ค์ƒ ๋ถˆ๊ฐ€๋Šฅํ•˜๋‹ค.

์ด๋ฅผ ์œ„ํ•ด JPA์—์„œ๋Š” JPQL์ด๋ผ๋Š” Entity์šฉ SQL์„ ์ œ๊ณตํ•œ๋‹ค.

 

 

๐Ÿ“Œ JPQL ํ‘œ์ค€ ๋ฌธ๋ฒ•

SQL ํ‘œ์ค€ ๋ฌธ๋ฒ•๊ณผ ๋งค์šฐ ์œ ์‚ฌํ•˜๋‹ค. ANSI (American National Standards Institute) ํ‘œ์ค€ SQL์˜ ๊ธฐ๋Šฅ์€ ์ „๋ถ€ ์ง€์›ํ•œ๋‹ค.

๋‹จ ์œ ์˜ํ•  ์ ์€ Entity๋ฅผ ๋Œ€์ƒ์œผ๋กœ ํ•˜๋Š” ์ฟผ๋ฆฌ๋ฌธ์ด๋‹ค. ๋‹น์—ฐํžˆ ์‹ค์ œ DB Query๋Š” ๋‹ค๋ฅด๊ฒŒ ์ฐํžŒ๋‹ค.

/* ์ฃผ์„์œผ๋กœ JPQL ์ฟผ๋ฆฌ๋ฌธ์„ ๋ณด์—ฌ์ค€๋‹ค */, ์•„๋ž˜๋Š” ์‹ค์ œ ์ƒ์„ฑ๋œ SQL๋ฌธ

์ฆ‰, ์ถ”์ƒํ™”๋œ SQL์„ ์‚ฌ์šฉํ•˜๋Š”๊ฑฐ๋ผ ํŠน์ • ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค SQL์— ์˜์กดํ•˜์ง€ ์•Š๋Š”๋‹ค.

 

 

๐Ÿ“Œ JPQL ์ƒ์„ฑ - JPA Criteria

JPQL์˜ ๊ธฐ๋Šฅ์€ ํ’๋ถ€ํ•˜์ง€๋งŒ, ์•„๋ฌด๋ž˜๋„ String ๊ฐ’์œผ๋กœ ์ง์ ‘ ์ž…๋ ฅํ•˜๊ธฐ์— ๋™์ ์ฟผ๋ฆฌ๋ฅผ ๋งŒ๋“ค๊ธฐ ๋„ˆ๋ฌด ๊นŒ๋‹ค๋กญ๋‹ค.

๋งŒ์•ฝ ํŒŒ๋ผ๋ฉ”ํƒ€๋ฅผ ๊ฐ€์ ธ์™€์„œ ์กฐ๊ฑด์„ ๋„ฃ์–ด์„œ ์ฟผ๋ฆฌ๋ฅผ ๋„ฃ๋Š”๋‹ค๊ณ  ์ƒ๊ฐํ•ด๋ณด์ž. JPQL ํ˜ธ์ถœ ๋ฉ”์„œ๋“œ๊ฐ€ ๋งค์šฐ ๋”๋Ÿฌ์›Œ์ง„๋‹ค.

๋ฌธ์ž์—ด์„ ํ•ฉ์น  ๋•Œ ์ƒ๊ธฐ๋Š” ๋ฒ„๊ทธ๋„ ๋งŽ๊ณ , ์‹ ๊ฒฝ์“ธ๊ฒŒ ๋„ˆ๋ฌด ๋งŽ๋‹ค.

๊ทธ๋ž˜์„œ Java JPA ํ‘œ์ค€์—์„œ ์ž๋ฐ” ์ฝ”๋“œ๋กœ ์ฟผ๋ฆฌ๋ฅผ ์ƒ์„ฑํ•  ์ˆ˜ ์žˆ๊ฒŒ Criteria๋ผ๋Š” JPQL Builder๋ฅผ ์ œ๊ณตํ•ด์ค€๋‹ค.

โžก ๊ทธ๋Ÿฌ๋‚˜ ๋„ˆ๋ฌด ์‚ฌ์šฉ๋ฒ•์ด ๋ณต์žกํ•ด์„œ ์•„๋ฌด๋„ ์•ˆ์“ด๋‹ค. ์˜คํ”ˆ์†Œ์Šค์ธ QueryDSL์„ ์‚ฌ์šฉํ•œ๋‹ค. 

์˜ˆ์ œ์˜ where ์ ˆ์„ ๋ณด์ž. ๊ฐ„๋‹จํ•œ ์ฟผ๋ฆฌ๋„ ์ €๋ ‡๊ฒŒ ๋‚˜์˜ค๋Š”๋ฐ, ์กฐ๊ฑด์ด ์กฐ๊ธˆ๋งŒ ์ถ”๊ฐ€๋˜๋„ ์‚ฌ์šฉํ•˜๊ธฐ๊ฐ€ ๋„ˆ๋ฌด ์–ด๋ ต๋‹ค.

// Criteria ์‚ฌ์šฉ ์ค€๋น„
CriteriaBuilder cb = em.getCriteriaBuilder(); 
CriteriaQuery<Member> query = cb.createQuery(Member.class); 

// ๋ฃจํŠธ ํด๋ž˜์Šค (์กฐํšŒ๋ฅผ ์‹œ์ž‘ํ•  ํด๋ž˜์Šค)
Root<Member> m = query.from(Member.class); 

// ์ฟผ๋ฆฌ ์ƒ์„ฑ 
CriteriaQuery<Member> cq = query.select(m).where(cb.equal(m.get("username"), “kim”)); 

// EntityManager์— Criteria ์ฟผ๋ฆฌ ์ „๋‹ฌ
List<Member> resultList = em.createQuery(cq).getResultList();

 

 

๐Ÿ“Œ QueryDSL (์˜คํ”ˆ์†Œ์Šค)

์„ค์ •์€ ์กฐ๊ธˆ ๊ท€์ฐฎ์ง€๋งŒ, Criteria์— ๋น„ํ•ด์„œ ์‚ฌ์šฉํ•˜๊ธฐ ๋งค์šฐ ํŽธํ•˜๋‹ค.

๋˜ํ•œ ์ž๋ฐ” ์ฝ”๋“œ๋กœ ์ž‘์„ฑ๋˜์—ˆ๊ธฐ์— ์žฌ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•˜๊ณ , ์ปดํŒŒ์ผ ์‹œ์ ์—์„œ ๋งŽ์€ ์˜ค๋ฅ˜๋ฅผ ์žก์„ ์ˆ˜ ์žˆ๋‹ค.

// Factory ์ƒ์„ฑ
JPAFactoryQuery query = new JPAQueryFactory(em);

//select m from Member m where m.age > 18
QMember m = QMember.member;

List<Member> list = 
 query.selectFrom(m)
 .where(m.age.gt(18)) 
 .orderBy(m.name.desc())
 .fetch();

QueryDSL๋„ ์ œ๋Œ€๋กœ ๊ณต๋ถ€ํ•˜๋ฉด JPA๊ธ‰ ๋ถ„๋Ÿ‰์ด ๋‚˜์˜ค๋ฏ€๋กœ, ์ด ์ •๋„๋งŒ ์†Œ๊ฐœํ•˜๊ณ  ๋„˜์–ด๊ฐ€๋„๋ก ํ•˜๊ฒ ๋‹ค.

์ฐธ๊ณ ๋กœ ์ด๋Š” Java JPA ํ‘œ์ค€ ๊ธฐ์ˆ ์ด ์•„๋‹ˆ๋ผ ์˜คํ”ˆ์†Œ์Šค์ด๋‹ค.

 

๋‹ค๋งŒ Criteria๋“  QueryDSL์ด๋˜ ๊ฒฐ๊ตญ JPQL ์„ ์ƒ์„ฑํ•ด์ฃผ๋Š” ๋„๊ตฌ์ด๋‹ค.

JPQL์˜ ๋™์ž‘์„ ์ดํ•ดํ•˜๊ณ  ์ž˜ ์‚ฌ์šฉํ• ์ค„ ์•ˆ๋‹ค๋ฉด ์œ„์™€ ๊ฐ™์€ ๋„๊ตฌ๋Š” ์‰ฝ๊ฒŒ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค. (์ดˆ๊ธฐ์„ค์ •๋งŒ ์กฐ๊ธˆ ๊ท€์ฐฎ์„ ๋ฟ)

 

 

๐Ÿ“Œ ๋„ค์ดํ‹ฐ๋ธŒ SQL

Oracle Connect by์™€ ๊ฐ™์ด ํ‘œ์ค€ SQL๋ฌธ๋ฒ•(ANSI)๋ฅผ ๋ฒ—์–ด๋‚˜๋Š” ๊ธฐ๋Šฅ์„ ์‚ฌ์šฉํ•˜๊ณ  ์‹ถ๊ฑฐ๋‚˜

์ •๋ง ์ฟผ๋ฆฌ๋กœ์ง์ด ๋ณต์žกํ•ด์„œ ์ง์ ‘ ์Œฉ ์ฟผ๋ฆฌ๋ฅผ ๋‚ ๋ฆฌ๊ณ  ์‹ถ์€ ๊ฒฝ์šฐ ์‚ฌ์šฉํ•œ๋‹ค.

  • ํŠน์ • ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค๋งŒ ์ง€์›ํ•˜๋Š” ํ•จ์ˆ˜, ๋ฌธ๋ฒ•
  • SQL ์ฟผ๋ฆฌ ํžŒํŠธ
  • ์ธ๋ผ์ธ ๋ทฐ, UNION, INTERSECT
  • ์Šคํ† ์–ด๋“œ ํ”„๋กœ์‹œ์ €

์œ„์™€ ๊ฐ™์€ ์ด์œ ๋กœ JPQL์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์—†๋Š” ๊ฒฝ์šฐ, Native SQL์„ ํ†ตํ•ด ์ง์ ‘ SQL์„ ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ๋‹ค.

String sql =  "SELECT ID, AGE, TEAM_ID, NAME FROM MEMBER WHERE NAME =`kim`"; 
 
List<Member> resultList = em.createNativeQuery(sql, Member.class).getResultList();

์–ด๋…ธํ…Œ์ด์…˜์„ ์ด์šฉํ•˜๋ฉด ์กฐ๊ธˆ ๋” ์‰ฝ๊ฒŒ ์ ์šฉ ๊ฐ€๋Šฅํ•˜๋‹ค.

@Entity
@NamedNativeQuery(
    name = "Member.memberSQL",
    query = "SELECT ID, AGE, NAME, TEAM_ID " +
            "FROM MEMBER WHERE AGE > ?",
            resultClass = Member.class
)
public class Member {.. }
TypedQuery<Member> nativeQuery =
    em.createNamedQuery("Member.memberSQL", Member.class)
      .setParameter(1, 20);

 

์–ด๋…ธํ…Œ์ด์…˜์œผ๋กœ ์‰ฝ๊ฒŒ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค. JDBC๋ฅผ ์ง์ ‘ ์“ฐ๋Š” ๊ฒƒ๊ณผ ๋‹ค๋ฅธ ์ ์€ Native SQL ์‚ฌ์šฉ ์‹œ ์—”ํ‹ฐํ‹ฐ๋ฅผ ์กฐํšŒํ•˜๊ณ , JPA๊ฐ€ ์ง€์›ํ•˜๋Š” ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ์˜ ๊ธฐ๋Šฅ์„ ๊ทธ๋Œ€๋กœ ์ด์šฉ ๊ฐ€๋Šฅํ•˜๋‹ค.

 

์ฐธ๊ณ ๋กœ ์ ์ ˆํ•˜๊ฒŒ ์„ค์ •๋งŒ ํ•œ๋‹ค๋ฉด JPA์™€ ๋˜‘๊ฐ™์ด ๊ฒฐ๊ณผ ๋งคํ•‘( getResultList() )์œผ๋กœ ๋ฐ›์•„์˜ฌ ์ˆ˜๋„ ์žˆ๋‹ค.

๋”๋ณด๊ธฐ
@Entity
@SqlResultSetMapping( name = "memberWithOrderCount",
    entities = {@EntityResult (entityClass = Member.class)},
    columns = {@ColumnResult (name = "ORDER_COUNT")}
)
@NamedNativeQuery(
    name = "Member.memberWithOrderCount", // ๋„ค์ž„๋“œ ์ฟผ๋ฆฌ ์ด๋ฆ„(ํ•„์ˆ˜)
    query = "SELECT M.ID, AGE, NAME, TEAM_ID, I.ORDER_COUNT" + // SQL ์ฟผ๋ฆฌ(ํ•„์ˆ˜)
            "FROM MEMBER M" +
            "LEFT JOIN " +
            "    (SELECT IM.ID, COUNT(*) AS ORDER_COUNT " +
            "    FROM ORDERS O, MEMBER IM" +
            "    WHERE O.MEMBER_ID = IM.ID) I " +
            "ON M.ID = I.ID",
    SqlResultSetMapping = "memberWithOrderCount" // ๊ฒฐ๊ณผ ๋งคํ•‘ ์‚ฌ์šฉ
)
public class Member { ... }
List<Object[]> resultList =
    em.createNamedQuery("Member.memberWithOrderCount")
      .getResultList();

 

 

๐Ÿ“Œ JDBC ์ง์ ‘์‚ฌ์šฉ (MyBatis, SpringJdbcTemplate๊ณผ ํ•จ๊ป˜ ์‚ฌ์šฉ)

์•„์˜ˆ JPA๋ฅผ ์•ˆ๊ฑฐ์น˜๊ณ  ์‚ฌ์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•.

๊ทธ๋ƒฅ ์‚ฌ์šฉํ•˜๋Š” ๊ฑฐ๋‹ค. ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ๋ฅผ ์•ˆ๊ฑฐ์น˜๊ณ  ์ง์ ‘ ์กฐํšŒํ•œ๋‹ค.

 

๊ฒฐ๊ตญ JPA๋„ ์ €์ˆ˜์ค€์—์„œ๋Š” JDBC๋กœ ๋™์ž‘ํ•œ๋‹ค. ์ž˜ ์‚ฌ์šฉํ•œ๋‹ค๋ฉด JPA์™€ JDBC๋ฅผ ํ•จ๊ป˜ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

์‹ค๋ฌด์—์„œ๋„ ์ฟผ๋ฆฌ๊ฐ€ ๋ณต์žกํ•ด์ง€๊ฑฐ๋‚˜ ์„ฑ๋Šฅ ํŠœ๋‹์ด ํ•„์š”ํ•˜๋‹ค๋ฉด SpringJdbcTemplate์œผ๋กœ JPA์™€ ํ•จ๊ป˜ ์‚ฌ์šฉํ•˜๋Š” ๊ฒฝ์šฐ๊ฐ€ ๋งŽ๋‹ค.

 

๋‹ค๋งŒ JDBC๋ฅผ ์ง์ ‘ ์‚ฌ์šฉํ•˜๋Š”๊ฑด ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ๋ฅผ ๊ฑฐ์น˜์ง€ ์•Š์œผ๋‹ˆ JPA์™€ ํ•จ๊ป˜ ์‚ฌ์šฉํ•œ๋‹ค๋ฉด DB์— ๋ฐ˜์˜๋˜์—ˆ๋Š”์ง€ ์ž˜ ํ™•์ธํ•˜๊ณ  ์‚ฌ์šฉํ•ด์•ผํ•œ๋‹ค. (์ˆ˜๋™ flush)

 

 

๐Ÿ“Œ ์š”์•ฝ

๋ณดํ†ต

  • JPQL
  • QueryDSL
  • JDBC API (SpringJdbcTemplate) - ๋‹จ ์ฟผ๋ฆฌ๊ฐ€ ์—„์ฒญ ๋ณต์žกํ•œ ๊ฒฝ์šฐ. ๋Œ€๋ถ€๋ถ„์€ QueryDSL ์„ ์—์„œ ์ฒ˜๋ฆฌ ๊ฐ€๋Šฅ

์ด๋ ‡๊ฒŒ 3๊ฐ€์ง€๋ฅผ ๋งŽ์ด ์‚ฌ์šฉํ•œ๋‹ค.

 

๐Ÿ“Œ JPQL ๋ฌธ๋ฒ•

๐Ÿ“‘ ๊ธฐ๋ณธ ๋ฌธ๋ฒ•

๊ทธ๋ƒฅ SQL ํ‘œ์ค€ ๋ฌธ๋ฒ•์ด๋‹ค.

  • select m from member as m m.age > 18
    ๋ฐ˜๋“œ์‹œ ๋ณ„์นญ(m)์€ ๋„ฃ์–ด์ฃผ์–ด์•ผํ•œ๋‹ค. [as m]์„ ์ƒ๋žตํ•˜๋”๋ผ๋„ ํ•˜์ด๋ฒ„๋„ค์ดํŠธ๋Š” ๋ฌธ์ œ๊ฐ€ ์—†์ง€๋งŒ, ํ‘œ์ค€ ๋™์ž‘์€ ์•„๋‹˜.
  • ์—”ํ‹ฐํ‹ฐ์™€ ์†์„ฑ (Member, m.age)๋Š” ๋Œ€์†Œ๋ฌธ์ž๋ฅผ ๊ตฌ๋ถ„ํ•œ๋‹ค.
  • JPQL ๋ฌธ๋ฒ• ํ‚ค์›Œ๋“œ (SELECT, from)๋Š” ๋Œ€์†Œ๋ฌธ์ž๋ฅผ ๊ตฌ๋ถ„ํ•˜์ง€ ์•Š๋Š”๋‹ค. 
  • ๋‹น์—ฐํ•œ๊ฑฐ์ง€๋งŒ FROM Entity ๋กœ ์‚ฌ์šฉํ•ด์•ผํ•œ๋‹ค. ํ…Œ์ด๋ธ” ์ด๋ฆ„์„ ์“ฐ๋Š”๊ฒŒ ์•„๋‹ˆ๋‹ค. ์—”ํ‹ฐํ‹ฐ์— ๋Œ€ํ•œ ์ถ”์ƒํ™”๋œ ์ฟผ๋ฆฌ์ด๋‹ค.

 

๊ทธ ์™ธ COUNT, SUM๋“ฑ์€ ์„ค๋ช…์ด ํ•„์š” ์—†์„์ •๋„๋กœ ์‚ฌ์šฉ๋ฒ•๋„ ์ง๊ด€์ ์ด๋‹ค.

select
 COUNT(m), //ํšŒ์›์ˆ˜
 SUM(m.age), //๋‚˜์ด ํ•ฉ
 AVG(m.age), //ํ‰๊ท  ๋‚˜์ด
 MAX(m.age), //์ตœ๋Œ€ ๋‚˜์ด
 MIN(m.age) //์ตœ์†Œ ๋‚˜์ด
from Member m

 


๐Ÿ“‘ ์ฟผ๋ฆฌ์‹คํ–‰๊ณผ ๊ฒฐ๊ณผ ๋ฐ˜ํ™˜

๋ฐ˜ํ™˜ ํƒ€์ž…์ด ๋ช…ํ™•ํ•˜์ง€ ์•Š๋‹ค๋ฉด Query ๊ฐ์ฒด๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค.

์˜ˆ) select m.username, m.age from Member m โžก String(username)๊ณผ int(age)๋ฅผ ํ•จ๊ป˜ ์กฐํšŒ. ํƒ€์ž…์„ ์•Œ ์ˆ˜ ์—†์Œ.

Query query = 
 em.createQuery("SELECT m.username, m.age from Member m");

 

๋ฐ˜ํ™˜ํƒ€์ž…์„ ์ด๋ฏธ ์•Œ๊ณ ์žˆ๋‹ค๋ฉด ์ œ๋„ค๋ฆญ์ธ TypeQuery๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ๋œ๋‹ค.

์ด ๊ฒฝ์šฐ createQurey ๋ฉ”์„œ๋“œ์˜ 2๋ฒˆ์งธ ์ธ์ž์— ํƒ€์ž…์„ ๋„˜๊ฒจ์ฃผ๋ฉด ๋œ๋‹ค.

TypedQuery<Member> query = 
 em.createQuery("SELECT m FROM Member m", Member.class);

 

๊ฒฐ๊ณผ ์กฐํšŒ๋Š” ์•„๋ž˜์™€ ๊ฐ™์ด ํ•  ์ˆ˜ ์žˆ๋‹ค.

query.getResultList(); // ์ปฌ๋ ‰์…˜. ๊ฐ’์ด ํ•˜๋‚˜ ์ด์ƒ, ๊ฒฐ๊ณผ๊ฐ€ ์—†๋‹ค๋ฉด ๋นˆ ๋ฆฌ์ŠคํŠธ ๋ฐ˜ํ™˜

query.getSingleResult(); // ๋‹จ์ผ๊ฐ์ฒด. ๊ฐ’์ด ๋‹จ ํ•˜๋‚˜, ๊ฒฐ๊ณผ๊ฐ€ ์—†๊ฑฐ๋‚˜ ๋‘˜ ์ด์ƒ์ด๋ฉด ์˜ˆ์™ธ๋ฅผ ๋ฐ˜ํ™˜
/*  javax.persistence.NoResultException :: ๊ฒฐ๊ณผ๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค.
    javax.persistence.NonUniqueResultException :: ๊ฒฐ๊ณผ๊ฐ€ ์œ ๋‹ˆํฌํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. (์—ฌ๋Ÿฌ๊ฐœ ๋ฐ˜ํ™˜) */

 

๋‹ค๋งŒ getSingleResult()๋Š” ๋…ผ๋ž€์ด ๋งŽ์€ ๋ฉ”์„œ๋“œ์ด๋‹ค.

์˜ˆ์™ธ๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋ฉด try - catch๋ฌธ์œผ๋กœ ๋ถ„๊ธฐ๋ฅผ ์ž‘์„ฑํ•ด์ค˜์•ผํ•˜๋Š”๋ฐ, ์ด๊ฒŒ ์—ฌ๋Ÿฌ๋ฒˆ ๋ฐ˜๋ณต๋˜๋ฉด ์ƒ๋‹นํžˆ ๋ฒˆ๊ฑฐ๋กญ๊ธฐ ๋•Œ๋ฌธ. ๊ทธ๋ž˜์„œ Spring Data JPA์—๋Š” ์ด๋ฅผ ์ถ”์ƒํ™”์‹œ์ผœ  null์ด๋‚˜ Optional์„ ๋ฐ˜ํ™˜ํ•˜๋„๋ก ๋™์ž‘ํ•œ๋‹ค. (๋‚ด๋ถ€ ์ฝ”๋“œ์—์„œ JPA catch๋ฅผ ์žก์•„์„œ ์ฒ˜๋ฆฌํ•œ๋‹ค.) 

 

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

์ด๋ฆ„ ๊ธฐ์ค€ ๋ฐ”์ธ๋”ฉ :name

TypedQuery<Member> query = 
 em.createQuery("SELECT m FROM Member m where m.username=:username ", Member.class);

// ์ฟผ๋ฆฌ ํŒŒ๋ผ๋ฉ”ํƒ€ ์ž…๋ ฅ
query.setParameter("username", usernameParam);

 

์œ„์น˜ ๊ธฐ์ค€ ๋ฐ”์ธ๋”ฉ ?n - ๋‹ค๋งŒ ์‚ฌ์šฉํ•˜์ง€๋ง๊ฒƒ. ์ˆœ์„œ๋ฅผ ๋ฐ”๊พธ๋ฉด ๋ฒ„๊ทธ๊ฐ€ ์‰ฝ๊ฒŒ ๋ฐœ์ƒํ•จ.

TypedQuery<Member> query = 
 em.createQuery("SELECT m FROM Member m where m.username=?1 ", Member.class);

// ์ฟผ๋ฆฌ ํŒŒ๋ผ๋ฉ”ํƒ€ ์ž…๋ ฅ
query.setParameter(1, usernameParam);

 

๋‹ค๋งŒ ์œ„์™€ ๊ฐ™์ด ์ฟผ๋ฆฌ๋ฅผ ๋ฉ”์„œ๋“œ๋กœ ๋ถ„๋ฆฌํ•ด์„œ ์‚ฌ์šฉํ•˜๋Š” ๊ฒฝ์šฐ๋Š” ๊ฑฐ์˜ ์—†๋‹ค.

๋ฉ”์„œ๋“œ ์ฒด์ด๋‹์„ ์ด์šฉํ•ด ํ•œ๋ฒˆ์— ์ ๋Š” ๊ฑธ ๊ถŒ์žฅํ•œ๋‹ค.

em.createQuery("SELECT m FROM Member m where m.username=:username ", Member.class)
     .setParameter("username", "member1")
     .getSingleResult();

 

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

ํ”„๋กœ์ ์…˜์€ Select ์ ˆ์— ์กฐํšŒํ•  ๋Œ€์ƒ์„ ์ง€์ •ํ•˜๋Š” ๊ฒƒ์„ ์˜๋ฏธํ•œ๋‹ค. DB ํ”„๋กœ์ ์…˜์ด๋ž‘ ๋น„์Šทํ•œ ์˜๋ฏธ.

ํ”„๋กœ์ ์…˜ ๋Œ€์ƒ: ์—”ํ‹ฐํ‹ฐ, ์ž„๋ฒ ๋””๋“œ ํƒ€์ž…, ์Šค์นผ๋ผ ํƒ€์ž…(์ˆซ์ž, ๋ฌธ์ž๋“ฑ ๊ธฐ๋ณธ ๋ฐ์ดํ„ฐ ํƒ€์ž…)

DB์™€ ๋‹ค๋ฅด๊ฒŒ JPA์—๋Š” [์—”ํ‹ฐํ‹ฐ, ์ž„๋ฒ ๋””๋“œ] ํƒ€์ž…์ด๋ž€ ๊ฐœ๋…์ด ์žˆ์œผ๋‹ˆ๊นŒ.

 

๐Ÿšฉํ€ด์ฆˆ - ์•„๋ž˜์˜ ์ฟผ๋ฆฌ๋Š” Member ๊ฐ์ฒด์˜ list๋ฅผ ๋ฐ˜ํ™˜ํ•œ๋‹ค.

๊ทธ๋ ‡๋‹ค๋ฉด ๋ฆฌ์ŠคํŠธ ์•ˆ์— ์žˆ๋Š” ๊ฐ๊ฐ์˜ 'Member' ๊ฐ์ฒด๋Š” ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ์— ๊ด€๋ฆฌ๊ฐ€ ๋ ๊นŒ? ์•ˆ๋ ๊นŒ?

์ •๋‹ต : ๋œ๋‹ค. List ์•ˆ์— ์žˆ๋Š” ๋ชจ๋“  ๊ฐ์ฒด๊ฐ€ ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ์— ์ €์žฅ๋œ๋‹ค.

๊ทธ๋ž˜์„œ ์—”ํ‹ฐํ‹ฐ ํ”„๋กœ์ ์…˜์ด๋ผ๋Š” ๋ง๋กœ ๋”ฐ๋กœ ์–ธ๊ธ‰ํ•˜๋Š” ๊ฒƒ์ด๋‹ค. ์ด๋Š” ๋‹น์—ฐํžˆ ์ €์žฅ๋˜๋Š”๊ฒŒ ์•„๋‹ˆ๋‹ค.

List ์•ˆ์— ์žˆ๋Š” Member๋ฅผ ๋ณ€๊ฒฝํ•ด๋„, ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ๊ฐ€ ๋™์ž‘ํ•ด์„œ Dirty-Checking์„ ํ•ด์ค€๋‹ค.

 

๋‹น์—ฐํ•œ๊ฑฐ์ง€๋งŒ ์ž„๋ฒ ๋””๋“œ ํƒ€์ž…์€ '๊ฐ’' ์ด๊ธฐ ๋•Œ๋ฌธ์— ์กฐํšŒํ•  ๋•Œ ์†Œ์†๋œ Entity๋ฅผ ์ด์šฉํ•ด์„œ ๊ฐ€์ ธ์™€์•ผํ•œ๋‹ค.

em.createQuery("SELECT o.address FROM Order o", Address.class)
// SELECT address FROM Address a ๋Š” ๋ถˆ๊ฐ€๋Šฅ.

 

์Šค์นผ๋ผ ํƒ€์ž…(๊ทธ๋ƒฅ ๊ฐ’)์˜ ๊ฒฝ์šฐ์—๋Š” ์•„๋ž˜์™€ ๊ฐ™์ด ์‚ฌ์šฉํ•˜๋ฉด๋œ๋‹ค.

em.createQuery("SELECT m.name FROM Member m")

 

๊ทธ๋Ÿฐ๋ฐ ๋งŒ์•ฝ ๊ฐ’์ด 2๊ฐœ๊ฐ€ ๋„˜๋Š”๋‹ค๋ฉด ์–ด๋–ป๊ฒŒ ๋ฐ›์•„์™€์•ผํ• ๊นŒ? ์ž„๋ฒ ๋””๋“œ ํƒ€์ž…์€ Class๋กœ ๋ฌถ์—ฌ์žˆ์ง€๋งŒ ์Šค์นผ๋ผ๋Š” ๊ทธ๋ƒฅ ๊ฐ’์ธ๋ฐ?

em.createQuery("SELECT m.name, m.age FROM Member m") // name(String)๊ณผ age(Int)๋ฅผ ํ•จ๊ป˜ ๋ฐ›์•„์˜ค๋Š”๋ฒ•??

์ด ๋•Œ๋Š” TypeQuery ๋Œ€์‹ ๋ฅผ ๊ทธ๋ƒฅ Query๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ๋œ๋‹ค.

๊ทธ๋Ÿผ ๋‚ด๋ถ€์ ์œผ๋กœ Object 2์ฐจ์› ๋ฐฐ์—ด์ด ๋ฐ˜ํ™˜๋œ๋‹ค.

ํƒ€์ž…์„ ์ง€์ •ํ•ด์ฃผ์ง€ ์•Š์œผ๋ฉด ์›์†Œ๊ฐ’์œผ๋กœ Object[ username, age ] ๊ฐ€ ๋“ค์–ด๊ฐ€์žˆ๋‹ค.

 

 

์ฐธ๊ณ ๋กœ List<Object[]>๋กœ ์‚ฌ์šฉํ•˜๋ฉด TypeQuery๋ฅผ ์‚ฌ์šฉํ•ด์„œ ๊ฐ€์ ธ์˜ค๊ฒŒ๋œ๋‹ค. ์‚ฌ์šฉ๋ฒ•์€ ๋™์ผํ•˜๋‹ค.

List<Object[]> resultList = em.createQuery("select m.username, m.age from Member m");
								.getResultList();
                                
Object[] result = resultList.get(0);
// result[0] == username1
// result[1] == age1

 

์กฐ๊ธˆ ๋” ๊น”๋”ํ•œ ๋ฐฉ๋ฒ•์€ new ๋ช…๋ น์–ด๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด๋‹ค.

DTO๋ฅผ ๋ฐ”๋กœ ๋งŒ๋“ค์–ด์„œ ๋ฐ˜ํ™˜๋ฐ›์„ ์ˆ˜ ์žˆ๋‹ค. ๋‹ค๋งŒ ์ „์ฒด ํŒจํ‚ค์ง€๋ช…์„ ๋‹ค ์ ์–ด์ค˜์•ผํ•œ๋‹ค๋Š” ๋‹จ์ ์ด ์žˆ๋‹ค.

* ๋‚˜์ค‘์— ์ฟผ๋ฆฌ๋นŒ๋” (QueryBuilder)๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ํŒจํ‚ค์ง€๋ช…์„ ์‰ฝ๊ฒŒ ์ž…๋ ฅํ•  ์ˆ˜ ์žˆ๋‹ค.

SELECT new com.mypackage.UserDTO(m.username, m.age) FROM Member m
List<MemberDTO> result = em.createQuery("SELECT new jpabook.jpql.UserDTO(m.username, m.age) FROM Member m")
      		  .getResultList();

 

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

DB SQL์„ ์จ๋ดค๋‹ค๋ฉด ์•Œ๊ฒ ์ง€๋งŒ, ํŽ˜์ด์ง• ์ฟผ๋ฆฌ๋Š” ์–ธ์ œ๋‚˜ ๊ณจ์นซ๊ฑฐ๋ฆฌ์˜€๋‹ค.

-- MYSQL
SELECT
     M.ID AS ID,
     M.AGE AS AGE,
     M.TEAM_ID AS TEAM_ID,
     M.NAME AS NAME 
FROM
     MEMBER M 
ORDER BY
     M.NAME DESC LIMIT ?, ?
-- Oracle
SELECT * 
FROM
  ( SELECT ROW_.*, ROWNUM ROWNUM_ 
    FROM
    	 ( SELECT
              M.ID AS ID,
              M.AGE AS AGE,
              M.TEAM_ID AS TEAM_ID,
              M.NAME AS NAME 
          FROM MEMBER M 
          ORDER BY M.NAME 
          ) ROW_ 
     WHERE ROWNUM <= ?
  ) 
WHERE ROWNUM_ > ?

๊ทธ๋ž˜์„œ JPA์—์„œ๋Š” ํŽ˜์ด์ง•์„ ๋‹จ 2๊ฐœ๋กœ ์ถ”์ƒํ™”ํ•œ API๋ฅผ ์ œ๊ณตํ•ด์ค€๋‹ค.

1๋ฒˆ๋ถ€ํ„ฐ 10ํŽ˜์ด์ง€๊นŒ์ง€..์™€ ์‹ ์„ธ๊ณ„! (์ฐธ๊ณ ๋กœ ์‹ค์ œ ์ฟผ๋ฆฌ๋Š” ์œ„์˜ ์˜ˆ์ œ์ฒ˜๋Ÿผ ์ฐํžŒ๋‹ค.)

 

๐Ÿ“‘ JPQL ์กฐ์ธ

๊ฐ„๋‹จํ•˜๋‹ค.

๋ฌผ๋ก  ์กฐ์ธ๋ฌธ์„ ์ง์ ‘ ์‚ฌ์šฉํ•˜์ง€ ์•Š์•„๋„ ์กฐํšŒํ• ๋•Œ ์กฐ์ธ์ด ํ•„์š”ํ•˜๋ฉด, Join SQL์ด ๋‚˜๊ฐ€๊ฒŒ ๋œ๋‹ค.

ํ•˜์ง€๋งŒ ๊ฐ€๋Šฅํ•˜๋ฉด JPQL๋„ ๋ช…์‹œ์ ์ธ Join๋ฌธ์„ ์‚ฌ์šฉํ•ด์ฃผ์ž. DB ํŠœ๋‹ ํ• ๋•Œ ๋„์›€๋˜๊ธฐ๋„ํ•˜๊ณ , ๋˜๋„๋ก์ด๋ฉด SQL๊ณผ ๋น„์Šทํ•˜๊ฒŒ ๊ตฌ์„ฑํ•˜๋Š”๊ฒŒ ์ข‹๋‹ค.

(๋‚ด๋ถ€์กฐ์ธ ์ค‘ ํ•˜๋‚˜์ธ ์„ธํƒ€ ์กฐ์ธ)์€ ํŠน์ • ์กฐ๊ฑด(=, &amp;gt;, &amp;lt;)์œผ๋กœ ์กฐ์ธํ•˜๋Š” ๊ฒƒ์„ ์˜๋ฏธํ•œ๋‹ค.

 

๐Ÿ“‘ ์‹ ๊ธฐ๋Šฅ - ์กฐ์ธ ON์ ˆ

(JPA 2.1 + ํ•˜์ด๋ฒ„๋„ค์ดํŠธ 5.1)๋ถ€ํ„ฐ ON์ ˆ์„ ํ™œ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค. ์—ฐ๊ด€ ๊ด€๊ณ„๊ฐ€ ์—†๋Š” ์™ธ๋ถ€์กฐ์ธ์ด ๊ฐ€๋Šฅํ•˜๋‹ค. (JPQL)

๋‹ค๋งŒ ๊ทธ ์ดํ•˜ ๋ฒ„์ „์„ ์‚ฌ์šฉํ•˜๋Š” ๊ธฐ์—…(SpringBoot 1.0 ๋ฒ„์ „ ์‹œ์ ˆ)์€ ๊ฑฐ์˜ ์—†์œผ๋ฏ€๋กœ, ๊ทธ๋ƒฅ ๊ธฐ๋ณธ๊ธฐ๋Šฅ์ด๋ผ๊ณ  ์ƒ๊ฐํ•ด๋„ ์ข‹๋‹ค.

ON์œผ๋กœ ์กฐ์ธ ์กฐ๊ฑด(์กฐ์ธ๋Œ€์ƒ ํ•„ํ„ฐ๋ง)์ด ๊ฐ€๋Šฅํ•˜๋‹ค.

 

๐Ÿ“‘ ์„œ๋ธŒ์ฟผ๋ฆฌ

ํฌ๊ฒŒ ์–ด๋ ต์ง€ ์•Š๋‹ค. 

--ํŒ€A ์†Œ์†์ธ ํšŒ์›
select m from Member m
where exists (select t from m.team t where t.name = 'ํŒ€A')

--์ „์ฒด ์ƒํ’ˆ ๊ฐ๊ฐ์˜ ์žฌ๊ณ ๋ณด๋‹ค ์ฃผ๋ฌธ๋Ÿ‰์ด ๋งŽ์€ ์ฃผ๋ฌธ๋“ค
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)

 

๋‹ค๋งŒ 2๋ฒˆ ์˜ˆ์ œ์ฒ˜๋Ÿผ ์„œ๋ธŒ์ฟผ๋ฆฌ๊ฐ€ ์™ธ๋ถ€ ์ฐธ์กฐ๊ฐ’์ด ์žˆ์œผ๋ฉด ์„ฑ๋Šฅ์ด ์ข‹์ง€์•Š๋‹ค.

 

๋‹ค๋งŒ JPA ์—์„œ๋Š” WHERE, HAVING ์„œ๋ธŒ์ฟผ๋ฆฌ๋งŒ ์ œ๊ณตํ•˜๊ณ , ํ•˜์ด๋ฒ„๋„ค์ดํŠธ์—์„œ๋Š” SELECT ์„œ๋ธŒ์ฟผ๋ฆฌ๊นŒ์ง€ ์ง€์›ํ•œ๋‹ค.

์ธ๋ผ์ธ ๋ทฐ(FROM ์ ˆ ์„œ๋ธŒ์ฟผ๋ฆฌ)๋Š” JPQL์—์„œ๋Š” ๋ถˆ๊ฐ€๋Šฅํ•˜๋‹ค 

from ์„œ๋ธŒ์ฟผ๋ฆฌ๋Š” ๋ถˆ๊ฐ€๋Šฅ. ์กฐ์ธ์œผ๋กœ ํ’€์–ด์„œ ํ•ด๊ฒฐํ•ด์•ผํ•จ.

์ด๊ฒŒ ์•ˆ๋˜๋Š” ์ด์œ ๋Š” ORM ๊ธฐ์ˆ ์˜ ํ•œ๊ณ„..๋ญ ์ด๋Ÿฐ๊ฑด ์•„๋‹ˆ๊ณ  ํ•˜์ด๋ฒ„๋„ค์ดํŠธ JPQL Parser๊ฐ€ ์•„์ง ์ธ๋ผ์ธ๋ทฐ๋ฅผ ์ง€์›ํ•˜์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค. SQL ์ฟผ๋ฆฌ๋ฅผ ์ƒ์„ฑํ•˜๋Š”๋ฐ ์–ด๋ ค์›€์ด ์žˆ์–ด์„œ ๊ทธ๋Ÿฌํ•œ ๋“ฏ ํ•˜๋‹ค. ํ•˜์ด๋ฒ„๋„ค์ดํŠธ 6.0์ด ๋‚˜์˜ค๋ฉด ํ•ด๊ฒฐ๋  ์ˆ˜๋„ ์žˆ๋‹ค.

 

๋งŒ์•ฝ ์ธ๋ผ์ธ๋ทฐ๋ฅผ ์กฐ์ธ์œผ๋กœ ํ’€ ์ˆ˜๊ฐ€ ์—†๋Š” ์ƒํ™ฉ์ด๋ผ๋ฉด ์•„๋ž˜์™€ ๊ฐ™์€ ๋Œ€์•ˆ์ด ์žˆ๋‹ค.

1. ์กฐ์ธ์œผ๋กœ ๋ณ€๊ฒฝํ•œ๋‹ค.

2. ์ฟผ๋ฆฌ๋ฅผ ์—ฌ๋Ÿฌ๊ฐœ๋กœ ๋ถ„๋ฆฌํ•œ๋‹ค.

3. ๊ทธ๋ž˜๋„ ๋‹ต์ด ์•ˆ๋‚˜์˜ค๋ฉด ๋„ค์ดํ‹ฐ๋ธŒ ์ฟผ๋ฆฌ๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค.

 

์กฐ์ธ์€ ๋ง ๊ทธ๋Œ€๋กœ ํ…Œ์ด๋ธ” 2๊ฐœ๋ฅผ ๊ฐ€์ ธ์˜ค๋Š”๊ฑฐ๊ณ , ๋„ค์ดํ‹ฐ๋ธŒ๋Š” ๊ทธ๋ƒฅ ์Œฉ SQL์„ ์“ฐ๋Š”๊ฑฐ๋‹ค.

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

์˜ˆ์ œ ํ…Œ์ด๋ธ” ๊ตฌ์กฐ

 

๊ทธ๋ฆฌ๊ณ  ์ธ๋ผ์ธ๋ทฐ(From์ ˆ ์„œ๋ธŒ์ฟผ๋ฆฌ)๊ฐ€ ํ•„์š”ํ•  ๋•Œ

-- ํŒ€๋‹น ๋‚˜์ด๊ฐ€ ๊ฐ€์žฅ ๋งŽ์€ ํšŒ์›์˜ ์ •๋ณด(username, age)๋ฅผ ์ถœ๋ ฅํ•˜๋ผ
SELECT m.*
FROM member m, (select team_id, max(age) as max_age from member group by team_id) m2
WHERE m.team_id = m2.team_id and m.age = m2.max_age;

 

์ด๋ ‡๊ฒŒ 2๊ฐœ๋กœ ์ชผ๊ฐœ๋ผ๋Š” ๋ง์ด๋‹ค. ์กฐ๊ธˆ ๋ฒˆ๊ฑฐ๋กญ๊ธด ํ•˜๋‹ค.

-- 1. ํŒ€๋‹น max(age)๋ฅผ ๋ฝ‘์•„๋ƒ„. Java ๋ณ€์ˆ˜๋กœ ๊ฐ’์„ ์ €์žฅํ•ด๋‘ 
select team_id, max(age) as max_age from member m2 group by team_id;

--2. ์ €์žฅํ•œ max(age)๋ฅผ ์ด์šฉํ•ด์„œ ์›ํ•˜๋Š” ํšŒ์›์„ ์กฐํšŒํ•จ.
select m.team_id, m.username, m.age from member m
where (m.team_id = 1 and m.age = 20) or (m.team_id=2 and m.age=30);

์˜ˆ์ œ ํ…Œ์ด๋ธ” ๊ตฌ์กฐ

 

๋‹ค๋งŒ ์œ„์—์„œ ๋งํ•œ ๊ฒƒ์ฒ˜๋Ÿผ, ์ฟผ๋ฆฌ๊ฐ€ ์ •๋ง ๋ณต์žกํ•ด์„œ JPQL๋กœ ๋งŒ๋“ค๊ธฐ ์–ด๋ ค์šด ๊ฒฝ์šฐ๊ฐ€ ์ข…์ข… ์žˆ๋‹ค.

๊ทธ๋• ๊ทธ๋ƒฅ ๋„ค์ดํ‹ฐ๋ธŒ ์ฟผ๋ฆฌ๋ฅผ ์‚ฌ์šฉํ•˜๊ฑฐ๋‚˜ ์ˆœ์ˆ˜ JDBC(SpringJDBCTemplate)๋ฅผ ์ด์šฉํ•ด์„œ ์Œฉ SQL์„ ์‚ฌ์šฉํ•˜๋ฉด ๋œ๋‹ค.

 

์˜์†์„ฑ ์ปจํ…์ŠคํŠธ flush๋งŒ ์ ์ ˆํ•˜๊ฒŒ ํ•ด์ค€๋‹ค๋ฉด, ํฐ ๋ฌธ์ œ์—†์ด ํ•จ๊ป˜ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

 

๐Ÿ“‘JPQL ํƒ€์ž… ํ‘œํ˜„

์šฐ๋ฆฌ๊ฐ€ ์ง์ ‘๋งŒ๋“  ์—”ํ‹ฐํ‹ฐ๋‚˜ ์ž„๋ฒ ๋””๋“œ ํƒ€์ž…์€ ํŒจํ‚ค์ง€๋ช…์„ ๊ทธ๋Œ€๋กœ ์“ฐ๋ฉด ์‚ฌ์šฉ์ด ๊ฐ€๋Šฅํ–ˆ๋‹ค.

๋ณดํ†ต์€ ์œ„์™€ ๊ฐ™์ด ํŒŒ๋ผ๋ฉ”ํƒ€๋ฅผ ๋„ฃ์–ด์„œ ๋ฉ”์„œ๋“œ๋กœ ํ• ๋‹นํ•˜๊ธฐ์— ํฌ๊ฒŒ ์–ด๋ ต์ง€ ์•Š๋‹ค.

์ด์™ธ์—๋„ JPQL ๊ตฌ๋ฌธ์— ์•„๋ž˜์™€ ๊ฐ™์€ ๊ธฐ๋ณธํƒ€์ž…๋“ค์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

์ด๋ ‡๊ฒŒ ๊ฒฐ๊ณผ๊ฐ’์— ์ƒ์ˆ˜๋ฅผ ๋ฐ•์•„๋„ฃ์„ ์ˆ˜๋„ ์žˆ๋‹ค. ('HELLO' , TRUE)

์ฐธ๊ณ ๋กœ ์—”ํ‹ฐํ‹ฐ ํƒ€์ž…์œผ๋กœ ์กฐํšŒ๋„ ๊ฐ€๋Šฅํ•˜๋‹ค.

@DiscriminatorValue์™€ ํ•จ๊ป˜ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

 

๐Ÿ“‘ ์กฐ๊ฑด CASE ์‹

JPQL์€ ๊ฐ„๋‹จํ•œ ์กฐ๊ฑด์‹ (case when else)๋ฅผ ์ œ๊ณตํ•ด์ค€๋‹ค.

์•„๋ž˜์™€ ๊ฐ™์€ ํŠน์ˆ˜ํ•œ ์กฐ๊ฑด์‹๋„ ์ œ๊ณตํ•ด์ค€๋‹ค.

์ด๋Š” JPA ํ‘œ์ค€ํ•จ์ˆ˜๋ผ์„œ, ๋ชจ๋“  DB์—์„œ ๋™์ผํ•˜๊ฒŒ ๋™์ž‘์„ ๋ณด์žฅํ•œ๋‹ค.

๊ทธ ์™ธ ์•„๋ž˜์™€ ๊ฐ™์€ JPQL ํ‘œ์ค€ ํ•จ์ˆ˜๋“ค์ด ์กด์žฌํ•œ๋‹ค. ์ƒ๊ฐ๋ณด๋‹ค ๋งŽ์ด ์—†๋‹ค.

 

๊ทธ ์™ธ ํŠน์ • DB์—์„œ๋งŒ ์ œ๊ณตํ•˜๋Š” ํ•จ์ˆ˜๋Š” ์•„๋ž˜์™€ ๊ฐ™์ด ์ •์˜ํ•  ์ˆ˜ ์žˆ๋‹ค.

๋ฌผ๋ก  ๊ทธ๋ƒฅ ๋˜๋Š”๊ฑด์•„๋‹ˆ๊ณ , ํ•ด๋‹น DB์˜ Dialect๋ฅผ ๋“ฑ๋กํ•ด์ฃผ์–ด์•ผํ•˜๋Š”๋ฐ ์ด๋ฏธ ๋‹ค์–‘ํ•œ ์ข…๋ฅ˜์˜ Dialect๋ฅผ ํ•˜์ด๋ฒ„๋„ค์ดํŠธ์—์„œ ์ œ๊ณตํ•ด์ฃผ๋ฏ€๋กœ ํŽธํ•˜๊ฒŒ ์“ธ ์ˆ˜ ์žˆ๋‹ค. ๋งŒ์•ฝ ๋‚ด๊ฐ€ ์“ฐ๋Š” DB๊ฐ€ ์—†๋‹ค๋ฉด ์ง์ ‘ Dialect๋ฅผ ๋“ฑ๋กํ•ด์•ผํ•œ๋‹ค. ๋ฌผ๋ก  ๊ทธ๋Ÿด ์ผ์€ ์—†์ง€๋งŒ

 

๐Ÿ“‘ ๊ฒฝ๋กœ ํ‘œํ˜„์‹

๊ฒฝ๋กœ ํ‘œํ˜„์‹์€ ๊ฐ์ฒด ๊ทธ๋ž˜ํ”„ํƒ์ƒ‰ (member.name)์„ ์˜๋ฏธํ•œ๋‹ค.

SQL์—๋Š” ์ด๋Ÿฐ๊ฒŒ ์—†์œผ๋‹ˆ๊นŒ, ์ด๋Ÿฐ ๊ฐ์ฒด ๊ทธ๋ž˜ํ”„ ํƒ์ƒ‰์„ JPQL ์—์„œ ์ œ๊ณตํ•˜๋Š” ๊ฒฝ๋กœํ‘œํ˜„์‹์ด๋ผ๊ณ  ๋ถ€๋ฅธ๋‹ค.

 

์ƒํƒœ, ๋‹จ์ผ ์—ฐ๊ด€, ์ปฌ๋ ‰์…˜ ์—ฐ๊ด€์„ ๊ตณ์ด ๊ตฌ๋ถ„ํ•˜๋Š” ์ด์œ ๋Š”, JPA์˜ ๋™์ž‘์ด ๋‹ฌ๋ผ์ง€๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.

 

๊ฐ๊ฐ์˜ ๋™์ž‘์€ ์•„๋ž˜์™€ ๊ฐ™๋‹ค.

๊ฒฐ๋ก ๋ถ€ํ„ฐ ์ด์•ผ๊ธฐ ํ•˜์ž๋ฉด, ๋ฌต์‹œ์  ์กฐ์ธ์ด ๋ฐœ์ƒํ•˜์ง€ ์•Š๋„๋ก JPQL์„ ๋งŒ๋“ค์ž.

๋‹น์—ฐํ•œ๊ฑฐ๊ธดํ•œ๋ฐ, ์ž„๋ฒ ๋””๋“œ ๊ฐ’ ํƒ€์ž…์˜ ๊ฒฝ์šฐ์—๋„ ํƒ์ƒ‰์ด ๊ฐ€๋Šฅํ•˜๋‹ค. Address.city&amp;nbsp;

m.team.name ์ฒ˜๋Ÿผ ๊ฐ์ฒด ๊ทธ๋ž˜ํ”„ ํƒ์ƒ‰์ด ๊ฐ€๋Šฅํ•˜๋‹ค.

์ปฌ๋ ‰์…˜ ์—ฐ๊ด€๊ด€๊ณ„๋Š” ํƒ์ƒ‰์€ ์•ˆ๋˜์ง€๋งŒ, ๋‚ด๋ถ€์—์„œ ์กฐ์ธ์€ ๊ทธ๋Œ€๋กœ ๋ฐœ์ƒํ•œ๋‹ค.

๊ทธ๋ƒฅ ๊ฐ์ฒด๊ฐ€ ์ปฌ๋ ‰์…˜(List) ์— ๋“ค์–ด๊ฐ€๋‹ˆ๊นŒ, List.size() ์ด๋Ÿฐ ๋ฉ”์„œ๋“œ๋ฐ–์— ํ˜ธ์ถœ์ด ์•ˆ๋˜์„œ ํƒ์ƒ‰์ด ์•ˆ๋˜๋Š”๊ฑฐ์ง€ [๋‹จ์ผ ๊ฐ’ ์—ฐ๊ด€๊ฒฝ๋กœ]์™€ ๋˜‘๊ฐ™์ด ์กฐ์ธ์€ ๋ฐœ์ƒํ•œ๋‹ค. ๋งŒ์•ฝ as๋กœ ๋ณ„์นญ์„ ์ฃผ๋ฉด ํƒ์ƒ‰๊ฐ€๋Šฅํ•˜๋‹ค.

์ด๋ ‡๊ฒŒ join ๊ตฌ๋ฌธ์„ ์ด์šฉํ•ด์„œ ๋ณ„๋ช…์„ ์ง€์ •ํ•ด์ฃผ๋ฉด team.member.username ์ด๋Ÿฐ ํƒ์ƒ‰์ด ๊ฐ€๋Šฅ.

์ฆ‰ JPQL์—์„œ๋Š” ์•„๋ฌด์ผ์ด ์—†๋Š” ๊ฒƒ ๊ฐ™์ง€๋งŒ, ์•„๋ฌด๋„ ๋ชจ๋ฅด๊ฒŒ SQL ์„ฑ๋Šฅ์ด ๊ตฌ๋ ค์ง„๋‹ค. ๋งค์šฐ ์กฐ์‹ฌ์Šค๋Ÿฝ๊ฒŒ ์‚ฌ์šฉํ•ด์•ผํ•œ๋‹ค.

๊ทธ๋ƒฅ ๋ฌต์‹œ์  ์กฐ์ธ์„ ์“ฐ์ง€๋ง๊ณ , ๋‚ด๋ถ€์—์„œ ์กฐ์ธ์ด ๋ฐœ์ƒํ•œ๋‹ค๋ฉด JPQL join ๊ตฌ๋ฌธ์„ ์ด์šฉํ•ด์„œ ๋ช…์‹œ์ ์œผ๋กœ ๋ฐ”๊ฟ”์ฃผ์ž.

๊ฐ„๋‹จํ•œ ์ฟผ๋ฆฌ์ธ๋ฐ, ์กฐ์ธ์ฟผ๋ฆฌ๊ฐ€ ๋ฐœ์ƒํ–ˆ๋‹ค. ๋‚˜์ค‘์— ์ด๋Ÿฐ๊ฑฐ ์ฐพ์•„์„œ DBํŠœ๋‹ํ•˜๋ ค๋ฉด ๋งค์šฐ ๊ท€์ฐฎ๋‹ค.

๋งŒ์•ฝ school.class.students.student.address.city ์ด๋ ‡๊ฒŒ ํƒ์ƒ‰์„ ํ•ด๋ฒ„๋ฆฌ๋ฉด

SQL ์ด๋„ˆ์กฐ์ธ์ด 7๋ฒˆ ๋ฐœ์ƒํ•œ๋‹ค. ๋„๋ฉ”์ธ ์„ค๊ณ„, ์„ฑ๋Šฅ ๋‘˜ ๋‹ค ๋”์ฐํ•˜๋‹ค.

์‹ค๋ฌด์—์„œ๋Š” ๋ช…์‹œ์  ์กฐ์ธ๋งŒ ์‚ฌ์šฉํ•˜์ž. SQL ํŠœ๋‹์ด ๋งค์šฐ ์ค‘์š”ํ•˜๋‹ค.

 

๐Ÿ“‘ join fetch(ํŒจ์น˜์กฐ์ธ)

์ฐธ๊ณ ๋กœ DB์—๋Š” ํŒจ์น˜์กฐ์ธ์ด๋ผ๋Š” ๊ฐœ๋…์ด ์—†๋‹ค.

JPA์—์„œ ์„ฑ๋Šฅ ์ตœ์ ํ™”๋ฅผ ์œ„ํ•ด ์ œ๊ณตํ•˜๋Š” ๊ธฐ๋Šฅ์œผ๋กœ, ์—ฐ๊ด€๋œ ์—”ํ‹ฐํ‹ฐ๋‚˜ ์ปฌ๋ ‰์…˜์„ SQLํ•œ๋ฐฉ์ฟผ๋ฆฌ๋กœ ๋ฐ”๊พธ๋Š” ๊ธฐ๋Šฅ์ด๋‹ค.

์ฐธ๊ณ ๋กœ Inner Join์œผ๋กœ ๊ฐ€์ ธ์˜ค๊ฒŒ ๋œ๋‹ค.

ํšŒ์›4 ๋Š” Team์ด ์—†์–ด์„œ ์ œ์™ธ๋จ.(inner join)

String jpql = "select m from Member m join fetch m.team";

List<Member> members = em.createQuery(jpql, Member.class)
    .getResultList();
    
for (Member member : members) {
    //ํŽ˜์น˜ ์กฐ์ธ์œผ๋กœ ํšŒ์›๊ณผ ํŒ€์„ ํ•จ๊ป˜ ์กฐํšŒํ•ด์„œ ์ง€์—ฐ ๋กœ๋”ฉX
    System.out.println("username = " + member.getUsername() + ", " +
        "teamName = " + member.getTeam().name());
}

 

 

์ผ๋Œ€๋‹ค (@OneToMany)๋„ ๋งˆ์ฐฌ๊ฐ€์ง€.

๋‹ค๋งŒ ์ด ๊ฒฝ์šฐ N+1 ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•˜๋Š” ๊ฑธ ์žŠ์ง€๋ง์ž. ์ด๋Š” Lazy๋กœ ์กฐํšŒํ•ด๋„ ๋งˆ์ฐฌ๊ฐ€์ง€์ด๋‹ค. (Lazy๋Š” ์‹ค ์‚ฌ์šฉ๊นŒ์ง€ ์กฐํšŒ ํƒ€์ด๋ฐ์„ ๋Šฆ์ถฐ์ค„ ๋ฟ, N+1์„ ์ตœ์ ํ™”์‹œ์ผœ์„œ ์ œ๊ฑฐํ•˜๋Š”๊ฒŒ ์•„๋‹ˆ๋‹ค)

 

๐Ÿ“‘ ํŒจ์น˜์กฐ์ธ๊ณผ Distinct

SQL์˜ DISTINCT๋Š” ์ค‘๋ณต์„ ์ œ๊ฑฐํ•˜๋Š” ๋ช…๋ น์ด๋‹ค.

ํ•˜์ง€๋งŒ ์ผ๋Œ€๋‹ค(@OneToMany)๊ด€๊ณ„์—์„œ๋Š” ์œ„ ๊ทธ๋ฆผ์ฒ˜๋Ÿผ ์ค‘๋ณต ๋ ˆ์ฝ”๋“œ(ํŒ€A-ํšŒ์›1, ํŒ€A-ํšŒ์›2, ํŒ€A-ํšŒ์›3...)๊ฐ€ ๋ฐœ์ƒํ•˜๊ธฐ ๋•Œ๋ฌธ์—, ํŒจ์น˜์กฐ์ธ๊ณผ ํ•จ๊ป˜ ์‚ฌ์šฉํ•˜๋ฉด DISTINCT๊ฐ€ ์ œ๋Œ€๋กœ ๋™์ž‘ํ•˜์ง€ ์•Š๋Š”๋‹ค. ๋‹ค๋Œ€์ผ ๊ด€๊ณ„์—์„œ๋Š” ์ค‘๋ณต์ด ๋ฐœ์ƒํ•  ์ผ์ด ์—†๋‹ค.

SQL์˜ DISTINCT๋Š” ๋ชจ๋“  ๊ฐ’์ด ๋˜‘๊ฐ™์•„์•ผ ์ œ๊ฑฐ๋œ๋‹ค. ํŒจ์น˜ ์กฐ์ธ๋•Œ๋ฌธ์— ์ œ๋Œ€๋กœ ์ œ๊ฑฐ๋˜์ง€ ์•Š๋Š”๋‹ค.

๋‹ค๋งŒ JPA์—์„œ ์—”ํ‹ฐํ‹ฐ๋ฅผ ์กฐํšŒํ•˜๋ฉด ์ œ๊ฑฐ๊ฐ€ ๋˜์–ด์žˆ๋Š”๋ฐ, ์ด๋Š” ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜(JPA)์—์„œ ์ค‘๋ณต๋œ ์—”ํ‹ฐํ‹ฐ๋ฅผ ์ œ๊ฑฐํ•˜๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.

๋ญ ๋ณ„ ์ƒ๊ฐ์—†์ด ์‚ฌ์šฉํ•  ์ˆ˜๋„ ์žˆ๊ฒ ์ง€๋งŒ, JPA์—์„œ ํ•œ๋ฒˆ ๋” ์ฒ˜๋ฆฌํ•˜๊ธฐ์— ์‹ค์ œ SQL ์ฟผ๋ฆฌ๋ฌธ์€ ๋‹ค๋ฅด๋‹ค๋Š”๊ฑธ ์ธ์ง€ํ•˜๊ณ ์žˆ์ž.

 

fetch ํ‚ค์›Œ๋“œ ์‚ฌ์šฉ์€, ๊ฐ์ฒด ๊ทธ๋ž˜ํ”„๋ฅผ SQL ํ•œ๋ฐฉ์— (์ฆ‰์‹œ๋กœ๋”ฉ) ๊ฐ€์ ธ์˜จ๋‹ค ์ƒ๊ฐํ•ด๋„ ๋œ๋‹ค.
ํŒจ์น˜์กฐ์ธ ์‚ฌ์šฉ์‹œ ์ด๋ ‡๊ฒŒ ์ฟผ๋ฆฌ๊ฐ€ ๋ฐ”๋€๋‹ค.

 

๐Ÿ“‘ ํŒจ์น˜์กฐ์ธ์˜ ํ•œ๊ณ„

ํŒจ์น˜์กฐ์ธ์€ ๋ง ๊ทธ๋Œ€๋กœ ๊ฐ์ฒด ๊ทธ๋ž˜ํ”„์— ์žˆ๋Š” ๋ชจ๋“  ๊ฐ์ฒด๋ฅผ ํ•œ๋ฐฉ์— ๊ฐ€์ ธ์˜ค๋Š” ์ฟผ๋ฆฌ๋‹ค.

๋งŒ์•ฝ ๋ณ„์นญ(m.username)์„ ์ฃผ๊ณ  ์ผ๋ถ€๋งŒ ์‚ฌ์šฉํ•˜๋ฉด, ๋‚˜๋จธ์ง€ ๋ฐ์ดํ„ฐ์— ๋Œ€ํ•ด์„œ JPA๊ฐ€ ์ด์ƒํ•˜๊ฒŒ ๋™์ž‘ํ•  ์ˆ˜ ์žˆ๋‹ค.  

ํ•˜์ด๋ฒ„๋„ค์ดํŠธ ๊ฒฝ๊ณ . ๋ฐ์ดํ„ฐ๊ฐ€ ๋ปฅํŠ€๊ธฐ ๋˜์–ด [ ํšŒ์›์ˆ˜ * ํŒ€์ˆ˜ * ํŒ€์ˆ˜ ] ์ด๋Ÿฐ ์‹์˜ ๋ฏธ์นœ ์ฟผ๋ฆฌ๊ฐ€ ๋‚˜์˜ฌ ์ˆ˜ ์žˆ๋‹ค.

๋ณ„์นญ๊ณผ ๊ฐ™์€ ์ด์œ ๋กœ ํŽ˜์ด์ง• API๋ฅผ ์‚ฌ์šฉํ•ด์„œ๋Š” ์•ˆ๋œ๋‹ค. ๋ฌผ๋ก  ๋ฐ์ดํ„ฐ ๋ปฅํŠ€๊ธฐ๊ฐ€ ๋˜์ง€์•Š๋Š” ManyToOne์€ ์ƒ๊ด€์—†๋‹ค.

๋ฐ์ดํ„ฐ๊ฐ€ ๋ปฅํŠ€๊ธฐ ๋˜์–ด ํŽ˜์ด์ง•์ด ์ด์ƒํ•˜๊ฒŒ ๋  ์ˆ˜ ์žˆ๋‹ค.

๋งŒ์•ฝ ๊ทธ๋Ÿฐ๊ฒŒ ํ•„์š”ํ•˜๋‹ค๋ฉด ๋‹ค๋Œ€์ผ(@ManyToOne)์—์„œ ๋ณ„๋„์˜ ์ฟผ๋ฆฌ๋กœ ์ง์ ‘ ๊ฐ€์ ธ์˜ค๋„๋ก ํ•˜์ž.

 

์‚ฌ์šฉํ•˜์ง€ ์•Š๋Š” ๋‚˜๋จธ์ง€ ๋ฐ์ดํ„ฐ๊ฐ€ ์‚ญ์ œ๋˜๊ฑฐ๋‚˜ ์ œ๋Œ€๋กœ ๋ฐ˜์˜๋˜์ง€ ์•Š์„ ์ˆ˜ ์žˆ๋‹ค. (์ •ํ•ฉ์„ฑ ์ด์Šˆ) ํŒจ์น˜ ์กฐ์ธ์€ ๊ฐ์ฒด ๊ทธ๋ž˜ํ”„์— ์žˆ๋Š” ๋ฐ์ดํ„ฐ๋ฅผ ์ „๋ถ€ ๋‹ค ๊ฐ€์ ธ์˜ค๋„๋ก ์„ค๊ณ„๋˜์—ˆ์œผ๋ฏ€๋กœ, ์ด๋Ÿฌํ•œ ์˜ค๋ฅ˜๋ฅผ ๋ณด์žฅํ•ด์ฃผ์ง€ ์•Š๋Š”๋‹ค.

 

โœ” ๋‹ค๋งŒ ์•„๋ž˜์™€ ๊ฐ™์€ ๊ฒฝ์šฐ, ์กฐ์ธ ํŒจ์น˜๋ฅผ ์ ์„ ๋•Œ ๋ณ„์นญ์„ ์‚ฌ์šฉํ•˜๊ธฐ๋„ ํ•œ๋‹ค.

๋‹ค๋งŒ join fetch๋ฅผ ์ ๊ธฐ ์œ„ํ•ด์„œ ์‚ฌ์šฉํ•œ๊ฑฐ์ง€, ๋ณ„์นญ์œผ๋กœ m.username ์ด๋Ÿฐ๊ฑธ ์“ฐ๋Š”๊ฑด ์ ˆ๋Œ€๊ธˆ์ง€.

 

๋งˆ์ง€๋ง‰์œผ๋กœ ๋‘˜ ์ด์ƒ์˜ ์ปฌ๋ ‰์…˜์„ ํŒจ์น˜์กฐ์ธํ•˜๋ฉด ์•ˆ๋œ๋‹ค. ์ผ๋Œ€๋‹ค(@OneToMany)๋„ ๋ฐ์ดํ„ฐ๊ฐ€ ๋ปฅํŠ€๊ธฐ ๋˜๋Š”๋ฐ, (@OneToManyToMany) ์ด๋ ‡๊ฒŒ ํ•ด๋ฒ„๋ฆฌ๋ฉด ์ •ํ•ฉ์„ฑ์ด ๊นจ์งˆ ์ˆ˜ ์žˆ๋‹ค.

 

 

๐Ÿ“‘ ํŒจ์น˜์กฐ์ธ์˜ ํŠน์ง•๊ณผ ํ•œ๊ณ„

 

 

๐Ÿ“Œ ๋ฒŒํฌ ์—ฐ์‚ฐ (์ˆ˜์ •,์‚ญ์ œ)

JPA๋Š” ์ปค๋ฐ‹ ์‹œ์ ์— Entity์˜ ๋ณ€๊ฒฝ์„ ๊ฐ์ง€ํ•ด์„œ ์ ์ ˆํ•œ ์ฟผ๋ฆฌ๋ฅผ ๋ฐœ์ƒ์‹œํ‚จ๋‹ค.

ํ•˜์ง€๋งŒ ์ž‘์—…์„ ํ•˜๋‹ค๋ณด๋ฉด ๋ฒŒํฌ์„ฑ ์ฟผ๋ฆฌ(ex ์žฌ๊ณ ๊ฐ€ 10๊ฐœ ๋ฏธ๋งŒ์ธ ์ƒํ’ˆ ์ „์ฒด์˜ ๊ฐ€๊ฒฉ์„ 20% ์ƒ์Šน) ์ž‘์—…์„ ํ•  ๋•Œ๋„ ์žˆ๋‹ค.

 

SQL๋กœ๋Š” ๊ฐ„๋‹จํ•œ ์ž‘์—…์ด์ง€๋งŒ JPA ๋ณ€๊ฒฝ๊ฐ์ง€๋กœ๋Š” ๋ฆฌ์†Œ์Šค๋„ ๋งŽ์ด ์žก์•„๋จน๊ณ , ์ฟผ๋ฆฌ๊ฐ€ ๋ณ€๊ฒฝ๋œ ๊ฐœ์ˆ˜๋งŒํผ ๋‚˜๊ฐˆ ์ˆ˜ ์žˆ๋‹ค.

๊ทธ๋ž˜์„œ ์ˆœ์ˆ˜ JPA์—์„œ๋„ ์ด๋Ÿฌํ•œ ์ž‘์—…์„ ์œ„ํ•ด executeUpdate() ๋ผ๋Š” ๋ฉ”์„œ๋“œ๋ฅผ ์ œ๊ณตํ•ด์คฌ์—ˆ๋‹ค.

  • ํ•ด๋‹น ๋ฉ”์„œ๋“œ๋Š” ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ๋ฅผ ๋ฌด์‹œํ•˜๊ณ , ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์— ์ง์ ‘ ์ฟผ๋ฆฌ๋ฅผ ๋‚ ๋ฆฐ๋‹ค.
    = ๋ฒŒํฌ์—ฐ์‚ฐ์€ ๋ณ€๊ฒฝ๊ฐ์ง€๊ฐ€ ์ž‘๋™ํ•˜์ง€ ์•Š๋Š”๋‹ค. ์‚ฌ์šฉํ•˜๋ฉด ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ์™€ Database์˜ ์ •ํ•ฉ์„ฑ์ด ๊นจ์ง„๋‹ค.
  • ๊ทธ๋ž˜์„œ ๋ฒŒํฌ์—ฐ์‚ฐ ์ดํ›„์— ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ๋ฅผ ์ดˆ๊ธฐํ™”(em.clear)ํ•˜๊ณ  ๋‹ค๋ฅธ ์ž‘์—…์„ ํ•˜๋Š” ๊ฒƒ์„ ๊ถŒ์žฅํ•œ๋‹ค.
    ๊ฐ€๋Šฅํ•˜๋ฉด ๋ฒŒํฌ์—ฐ์‚ฐ์„ ๋จผ์ € ํ•˜๊ณ  em.clear()๋ฅผ ํ•˜๋„๋ก ํ•˜์ž.
    ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ๋ฅผ ์™„์ „ํžˆ ๋น„์›Œ๋ฒ„๋ฆฌ๋ฉด ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์—์„œ ๋‹ค์‹œ ์กฐํšŒํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์ •ํ•ฉ์„ฑ์ด ๊นจ์ง€์ง€์•Š๋Š”๋‹ค.

์ฐธ๊ณ ๋กœ JPA ๋Š” Update, Delete ์ฟผ๋ฆฌ๋งŒ ์ง€์›ํ•˜๊ณ , ํ•˜์ด๋ฒ„๋„ค์ดํŠธ์—์„œ๋Š” select (insert into select๋ฌธ)๊นŒ์ง€ ์ถ”๊ฐ€ ์ง€์›ํ•œ๋‹ค.

// Update ๋ฒŒํฌ์—ฐ์‚ฐ
String query = "update Product p "+
    "set p.price = p.price * 1.1 " +
    "where p.stockAmount < :stockAmount";

int resultCount = em.createQuery(query)
                    .setParameter("stockAmount", 10)
                    .executeUpdate();
// Delete ๋ฒŒํฌ์—ฐ์‚ฐ. (Select ๋ฒŒํฌ์—ฐ์‚ฐ์€ JPA ์ŠคํŽ™์—๋Š” ์—†๊ณ , ํ•˜์ด๋ฒ„๋„ค์ดํŠธ๋งŒ ์ง€์›ํ•œ๋‹ค.)
int deletedCount = em.createQuery("DELETE FROM Country").executeUpdate();

์ฐธ๊ณ ๋กœ ํ•˜์ด๋ฒ„๋„ค์ดํŠธ๋งŒ ์ง€์›ํ•˜๋Š” ๋ฒŒํฌ์„ฑ insert into select๋Š” ์•„๋ž˜์™€ ๊ฐ™์€ ๋ฐฐ์น˜ ์ฟผ๋ฆฌ๋ฅผ ๋งํ•œ๋‹ค.

// Batch
INSERT INTO table1 (col1, col2) VALUES
(val11, val12),
(val21, val22),
(val31, val32);

๋ธ”๋กœ๊ทธ์˜ ์ •๋ณด

JiwonDev

JiwonDev

ํ™œ๋™ํ•˜๊ธฐ