์Šคํ”„๋ง

์Šคํ”„๋ง๊ณผ JPA๋ฅผ ์ด์šฉํ•œ ์›น๊ฐœ๋ฐœ_JPQL

JANNNNNN 2024. 3. 28. 11:49

๐Ÿค”JPQL๋ž€?(Java Persistence Query Language)

  • ๊ฐ์ฒด์ง€ํ–ฅ ์ฟผ๋ฆฌ!
  • JPQL์€ ํ…Œ์ด๋ธ”์„ ๋Œ€์ƒ์œผ๋กœ ์ฟผ๋ฆฌ๋ฅผ ์ƒ์„ฑํ•˜๋Š” ๊ฒƒ์ด ์•„๋‹Œ ์—”ํ‹ฐํ‹ฐ ๊ฐ์ฒด๋ฅผ ๋Œ€์ƒ์œผ๋กœ ์ฟผ๋ฆฌ๋ฅผ ์ƒ์„ฑ
  • JPQL๋กœ ์‹คํ–‰ํ•œ ์ฟผ๋ฆฌ๋„ ๊ฒฐ๊ตญ SQL๋กœ ๋ณ€ํ™˜๋˜์–ด ์‹คํ–‰
  • ๋”ฐ๋ผ์„œ ์‹คํ–‰๋˜๋Š” SQL ๋กœ๊น…ํ•˜์—ฌ ํ™•์ธํ•˜๋Š” ์ž‘์—…์ด ํ•„์š”
  • JPA์—์„œ ๊ด€๋ฆฌ๋˜๋Š” ์—”ํ‹ฐํ‹ฐ์— ๋Œ€ํ•œ SQL์€ ํŠธ๋žœ์žญ์…˜ ์ปค๋ฐ‹ ์‹œ์ ์ด์ง€๋งŒ JPQL์€ ์ฆ‰์‹œ ์‹คํ–‰ ๋จ

JPA๊ฐ€ ์žˆ๋Š”๋ฐ๋„ JPQL์„ ์‚ฌ์šฉํ•ด์•ผํ•˜๋‚˜์š”?

โžก๏ธJPA๋กœ๋Š” ๋ฐ์ดํ„ฐ๋ฅผ ์…€๋ ‰ํ•  ๋•Œ ์กฐ๊ฑด์— ํ•œ๊ณ„๊ฐ€ ์žˆ๊ธฐ ๋•Œ๋ฌธ์— JPQL์„ ์‚ฌ์šฉํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค!

Ex) 20๋Œ€ ์ด์ƒ์ธ ๋‚จ์„ฑ ์ค‘์—์„œ, ๊ตฌ๋งค๋ฅผ 2๋ฒˆ ์ด์ƒ ํ•œ ๊ณ ๊ฐ๋“ค์„ ๋Œ€์ƒ์œผ๋กœ ๋ฐ์ดํ„ฐ๋ฅผ ์กฐํšŒํ•ด์•ผํ•  ๋•Œ

โžก๏ธ์ฆ‰, SQL๊ด€์ ์—์„œ Where์ ˆ์ด ํ•„์š”ํ•œ ์ˆœ๊ฐ„์— JPQL์„ ์‚ฌ์šฉํ•˜๋ฉด ๋ฉ๋‹ˆ๋‹ค.

Selection

  • Selection – The FROM clause
  • FROM ์ ˆ์€ select ๋Œ€์ƒ์ด ๋˜๋Š” ์—”ํ‹ฐํ‹ฐ๋ฅผ ์ง€์ •ํ•˜๊ธฐ ์œ„ํ•ด ์‚ฌ์šฉ
SELECT a FROM Author (AS) a
  • AS๋Š” ์ƒ๋žต ๊ฐ€๋Šฅ
  • ์œ„ ์˜ˆ์‹œ์—์„œ Author๋Š” DB ํ…Œ์ด๋ธ”์„ ์˜๋ฏธํ•˜๋Š” ๊ฒƒ์ด ์•„๋‹Œ ์—”ํ‹ฐํ‹ฐ๋ฅผ ์˜๋ฏธ
  • ๋ฐ˜๋“œ์‹œ ๋ณ„์นญ์„ ๋ช…์‹œํ•ด์•ผ ํ•จ. ์œ„ ์˜ˆ์‹œ์—์„œ๋Š” a์— ํ•ด๋‹น
  • persist๊ฐ€ INSERT๋ฌธ์„ ๋Œ€์‹ ํ•จ

Types of JPA Queries: Query์˜ ์ข…๋ฅ˜

  • TypedQuery
    • ์ฟผ๋ฆฌ ์‹คํ–‰์˜ ๊ฒฐ๊ณผ๋กœ ๋ฐ˜ํ™˜๋  ํƒ€์ž…์„ ์•Œ๊ณ  ์žˆ์„ ๋•Œ
    • ์ถ”๊ฐ€์ ์ธ ํ˜•๋ณ€ํ™˜์ด ์—†๊ณ  ์œ ์—ฐํ•˜๊ณ  ์‰ฌ์šด ํ…Œ์ŠคํŠธ๋ฅผ ์ œ๊ณต

โžก๏ธJPQL์ฟผ๋ฆฌ๋ฅผ ์ ๊ณ , UserEntity.class๋ฅผ ๋ฐ˜ํ™˜(=Return type)ํ•œ๋‹ค๋Š” ๊ฒƒ์„ ๋ช…์‹œํ•ด์ค€๋‹ค. ๊ทธ๋ฆฌ๊ณ  TypedQuery์˜ ์ง€๋„ค๋ฆญํƒ€์ž…์— UserEntity๋ฅผ ์ง€์ •ํ•ด์ฃผ๋ฉด ๋œ๋‹ค!

+) ์œ„์˜ JPQL์€ ์‚ฌ์šฉ์ž๊ฐ€ ์ง€์ •ํ•œ id๊ฐ’์„ where์ ˆ๋กœ ๊ฐ€์ ธ์˜ค๊ฒ ๋‹ค๋Š” ๋œป.

  •  NamedQuery
    • ์—”ํ‹ฐํ‹ฐ์— ์‹คํ–‰๋  JPQL๊ณผ ๊ทธ ์ด๋ฆ„์„ ๋ช…์‹œํ•˜์—ฌ ์ง๊ด€์ ์œผ๋กœ ์ดํ•ด

โžก๏ธ์ด๋ฆ„ ๊ทธ๋Œ€๋กœ name์ด ์žˆ๋Š” ์ฟผ๋ฆฌ๋ผ์„œ Query๋งŒ ๋ณด๋ฉด ์ฝ๊ธฐ ์ „๊นŒ์ง€ ์–ด๋–ค ์ฟผ๋ฆฌ์ธ์ง€ ๋ชจ๋ฅด์ง€๋งŒ, name์ด ์žˆ์œผ๋ฉด ์ดํ•ด๋„ UP!!

  • NativeQuery
    • ์–˜๋Š” Native๋ผ๋Š” ์ด๋ฆ„์ฒ˜๋Ÿผ ๊ทธ๋ƒฅ SQL์ฟผ๋ฆฌ
    • ๊ทธ๋ ‡๊ธฐ ๋•Œ๋ฌธ์— JPQL์˜ ๊ตฌ๋ฌธ์— ์ œ์•ฝ ์—†์ด ๋Œ€์ƒ DB์— ๊ณง ๋ฐ”๋กœ SQL์‹คํ–‰๊ฐ€๋Šฅ
    • JPQL์ด๋‚˜ JPA์˜ ๊ด€๋ฆฌ๋ฅผ ๋ฒ—์–ด๋‚˜๋ฏ€๋กœ ์ด์‹์„ฑ์ด ๋–จ์–ด์งˆ ์ˆ˜ ์žˆ์Œ
    • ๊ทธ๋ž˜์„œ NativeQuery๋Š” ์ตœํ›„์˜ ์ˆ˜๋‹จ์œผ๋กœ ์ƒ๊ฐ..!
      • NativeQuery ๋‚ ๋ ธ๋Š”๋ฐ๋„ ๊ธฐ์กด JPA๋ณด๋‹ค ์„ฑ๋Šฅ์ด ์ข‹์œผ๋ฉด JPA์˜ ์—ฐ๊ด€๊ด€๊ณ„ ๋“ฑ์„ ์ž˜๋ชป ์‚ฌ์šฉํ–ˆ๋‹ค๋Š” ๋œป์ด๊ธฐ๋„ ํ•˜๋‹ค

๐Ÿ˜ถ์ž‘์„ฑํ•œ JPQL์„ ์‹คํ–‰ํ•˜๋ ค๋ฉด ์ฟผ๋ฆฌ ๊ฐ์ฒด๋ฅผ ๋งŒ๋“ค์–ด์•ผ ํ•œ๋‹ค!

  • ํƒ€์ž…์„ ๋ช…์‹œํ•  ์ˆ˜ ์žˆ์„ ๋•Œ
TypedQuery<String> query = em.createQuery("SELECT p.name from Person p", String.class);
List<String> resultList = query.getResultList();

โžก๏ธp.name์€ ๋‹น์—ฐํžˆ Stringํƒ€์ž…์œผ๋กœ ๋ฐ˜ํ™˜๋  ๊ฒƒ์ด๋ฏ€๋กœ ๋ฐ˜ํ™˜ ํƒ€์ž…๊ณผ ์ง€๋„ค๋ฆญํƒ€์ž…์— String.class๋ฅผ ์ ์–ด์ฃผ๋ฉด ๋œ๋‹ค.

โž•์œ„ JPQL์˜ ์ ˆ์€ SQL์˜ "SELECT NAME FROM PERSON"๊ณผ ๊ฐ™๋‹ค!

  • ํƒ€์ž…์„ ๋ช…์‹œํ•  ์ˆ˜ ์—†์„ ๋•Œ
Query query = em.createQuery("SELECT p.name, p.age from Person p");
List resultList = query.getResultList();
for(Object o: resultList){
    Object[] result = (Object[]) o; //๊ฒฐ๊ณผ๊ฐ€ ๋‘˜ ์ด์ƒ์ด๋ฉด Object[] ๋ฐ˜ํ™˜, ํ•˜๋‚˜๋ฉด Object ๋ฐ˜ํ™˜
    System.out.println("name = " + result[0]);
    System.out.println("age = " + result[1]);
}

โžก๏ธp.name์€ String์ด๊ณ  p.age๋Š” intํƒ€์ž…์ด๊ธฐ ๋•Œ๋ฌธ์— ์ด๋Ÿด ๊ฒฝ์šฐ์—๋Š” ์ž๋ฐ”์—์„œ ์ตœ์ƒ์œ„ ๊ณ„์ธต์ธ Object๋ฅผ ๋ฐ˜ํ™˜ํ•œ๋‹ค!

    ๋˜ํ•œ, ๊ฒฐ๊ณผ๊ฐ’์ด ๋‘๊ฐœ ์ด์ƒ์ด๊ธฐ ๋•Œ๋ฌธ์— List []์œผ๋กœ ๋ฐ˜ํ™˜ํ•œ๋‹ค.

๋Œ€ํ‘œ์ ์ธ JPQL์˜ ๊ธฐ๋Šฅ = "getResult"

  • query.getResultList()
    • ๊ฒฐ๊ณผ๊ฐ€ ํ•˜๋‚˜ ์ด์ƒ์ธ ๊ฒฝ์šฐ, ๋ฆฌ์ŠคํŠธ๋ฅผ ๋ฐ˜ํ™˜
    • ๊ฒฐ๊ณผ๊ฐ€ ์—†์œผ๋ฉด null๋ฐ˜ํ™˜
  • query.getSingleResult()
    • ์ผ์น˜ํ•˜๋Š” ํ•˜๋‚˜์˜ ์—”ํ‹ฐํ‹ฐ๋ฅผ ๋ฐ˜ํ™˜
    • ๊ฒฐ๊ณผ๊ฐ€ ์—†๊ฑฐ๋‚˜ ํ•œ ๊ฐœ๋ฅผ ์ดˆ๊ณผํ•˜๋ฉด ์˜ˆ์™ธ ๋ฐœ์ƒ
      • ์Šคํ”„๋ง ๋ฐ์ดํ„ฐ JPA์—์„œ๋Š” ํ•œ ๊ฐœ๋ฅผ ์ดˆ๊ณผํ•  ๋•Œ null ๋ฐ˜ํ™˜

โžก๏ธgetSingleResult๊ฐ€ ์กฐ๊ธˆ ๋” ์—„๊ฒฉํ•˜๋‹ค๊ณ  ๋ณผ ์ˆ˜ ์žˆ์Œ!

์˜ˆ์ œ : ๋ฐ˜ํ™˜ ํƒ€์ž…์„ ์•Œ ๋•Œ

@Entity
public class Person {
    @Id @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "PERSON_ID")
    private int id;

    private String name;
    private int age;

    @OneToMany(mappedBy = "person", cascade = CascadeType.REMOVE)
    private List<Address> addresses = new ArrayList<Address>();
...
@Entity
public class Address {
    @Id @GeneratedValue(strategy = GenerationType.IDENTITY)
    private int id;
    private String street;
    private String city;
    private String zipCode;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "PERSON_ID")
    private Person person;
    
   ...
package study;

import javax.persistence.*;
import java.util.List;

public class Main {
    public static void main(String[] args){
        EntityManagerFactory emf = Persistence.createEntityManagerFactory("playground");
        EntityManager em = emf.createEntityManager();

        EntityTransaction tx = em.getTransaction();

        try{
            tx.begin();
            Address address1 = new Address();
            address1.setCity("city1");
            address1.setStreet("street1");
            address1.setZipCode("zipCode1");

            Address address2 = new Address();
            address2.setCity("city1");
            address2.setStreet("street1");
            address2.setZipCode("zipCode1");

            Person person = new Person();
            person.setName("kim");
            person.setAge(20);

            address1.setPerson(person); //์—ฐ๊ด€๊ด€๊ณ„ ์ฃผ์ž…
            address2.setPerson(person);

            person.getAddresses().add(address1);
            person.getAddresses().add(address2);

            em.persist(person);
            em.persist(address1);
            em.persist(address2);

            em.flush();
            em.clear();

			----์—ฌ๊ธฐ์„œ๋ถ€ํ„ฐ JPQL์ฟผ๋ฆฌ!!-----
            TypedQuery<Person> query =
                    em.createQuery("SELECT p FROM Person AS p", Person.class);

            List<Person> resultList = query.getResultList();
            resultList.stream().forEach(v-> System.out.println("v = " + v));

            tx.commit();
        }catch (Exception e){
            tx.rollback();
        }finally {
            em.close();
        }
    }
}

โžก๏ธ์‹คํ–‰ํ•˜๋ฉด addresses ๊ฐ’์ด ์ด์ƒํ•˜๊ฒŒ ๋‚˜์˜ค๋Š”๋ฐ, ์ด๋Š” Person์—์„œ @OneToMany๊ฐ€ fetch์˜ ๊ธฐ๋ณธ ๊ฐ’์ด LAZY์ด๊ธฐ ๋•Œ๋ฌธ!

์‘์šฉversion : ๋ฐ˜ํ™˜ ํƒ€์ž…์„ ๋ชจ๋ฅผ ๋•Œ

Query query = em.createQuery(("SELECT p.name, p.age FROM Person p"));
            List resultList = query.getResultList();
            for(Object o:resultList){
                Object[] result = (Object[]) o;
                System.out.println("result[0]= " + result[0]);
                System.out.println("result[1]= " + result[1]);
            }

โžก๏ธ๋ฐ˜ํ™˜ํƒ€์ž…์„ ๋ชจ๋ฅผ ๊ฒฝ์šฐ return ํƒ€์ž…์„ ์ง€์ •ํ•ด์ฃผ์ง€ ์•Š๊ณ  ์ตœ์ƒ์œ„ ๊ณ„์ธต์ธ Object๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ํฐ ์ฐจ์ด์ ์ด๋‹ค!

โž•List ํƒ€์ž…์ด ์ €์žฅ๋  ๋•Œ๋Š” [kim, 20] ์ด๋Ÿฐ ์‹์œผ๋กœ ์ €์žฅ๋œ๋‹ค!