[7/27 TIL] JPA(SpringDataJPA)

yumyeonghanยท2023๋…„ 7์›” 28์ผ
0

๐Ÿƒํ”„๋กœ๊ทธ๋ž˜๋จธ์Šค ๋ฐฑ์—”๋“œ ๋ฐ๋ธŒ์ฝ”์Šค 4๊ธฐ ๊ต์œก๊ณผ์ •์„ ๋“ฃ๊ณ  ์ •๋ฆฌํ•œ ๊ธ€์ž…๋‹ˆ๋‹ค.๐Ÿƒ

SpringDataJPA

spring:
  datasource:
    driver-class-name: org.h2.Driver
    url: jdbc:h2:~/order;DB_CLOSE_ON_EXIT=FALSE
    username: sa
    password:

  jpa:
    open-in-view: false
    hibernate:
      ddl-auto: create-drop
    show-sql: true
    properties:
      hibernate.format_sql: true
  • ์Šคํ”„๋ง์—์„œ JPA๋ฅผ ํŽธ๋ฆฌํ•˜๊ฒŒ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋„๋ก ์ง€์›
  • ์ง์ ‘ ๋“ฑ๋กํ•ด์•ผ ํ–ˆ๋˜, JPA ๊ด€๋ จ ์„ค์ •(๋นˆ)์„ yml ํŒŒ์ผ์„ ํ†ตํ•ด ์ž๋™์œผ๋กœ ๋“ฑ๋ก
    • ๋ฐ์ดํ„ฐ ์†Œ์Šค, ์—”ํ‹ฐํ‹ฐ ๋งค๋‹ˆ์ €, ํŠธ๋žœ์žญ์…˜ ๋งค๋‹ˆ์ € ์„ค์ •
public interface OrderRepository extends JpaRepository<Order, String> {
}
  • ๋ฐ์ดํ„ฐ ์ €์žฅ ๊ณ„์ธต์— ๋Œ€ํ•œ ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ์ง€์›ํ•ด์ค˜์„œ CRUD ์ž‘์—…์„ ํŽธ๋ฆฌํ•˜๊ฒŒ ์‚ฌ์šฉ

๋ฉ”์†Œ๋“œ ์ฟผ๋ฆฌ

public interface OrderRepository extends JpaRepository<Order, String> {
    // ์ฃผ๋ฌธ ์ƒํƒœ(OrderStatus)๊ฐ€ 'OPEND'์ธ ๋ชจ๋“  ์ฃผ๋ฌธ ์กฐํšŒ
    List<Order> findAllByOrderStatus(OrderStatus orderStatus);
    // SELECT * FROM orders WHERE order_status = 'OPEND'

    // ์ฃผ๋ฌธ ์ƒํƒœ(OrderStatus)๊ฐ€ 'OPEND'์ธ ๋ชจ๋“  ์ฃผ๋ฌธ์„ ์ฃผ๋ฌธ ์ผ์‹œ(orderDatetime)๋ฅผ ๊ธฐ์ค€์œผ๋กœ ์˜ค๋ฆ„์ฐจ์ˆœ ์ •๋ ฌํ•˜์—ฌ ์กฐํšŒ
    List<Order> findAllByOrderStatusOrderByOrderDatetimeAsc(OrderStatus orderStatus);
    // SELECT * FROM orders WHERE order_status = 'OPEND' ORDER BY order_datetime ASC

    // ์ฃผ๋ฌธ ์ƒํƒœ(OrderStatus)๊ฐ€ 'DELIVERED'์ธ ๋ชจ๋“  ์ฃผ๋ฌธ์„ ์ฃผ๋ฌธ ๊ธˆ์•ก(totalAmount)์„ ๊ธฐ์ค€์œผ๋กœ ๋‚ด๋ฆผ์ฐจ์ˆœ ์ •๋ ฌํ•˜์—ฌ ์กฐํšŒ
    List<Order> findAllByOrderStatusOrderByTotalAmountDesc(OrderStatus orderStatus);
    // SELECT * FROM orders WHERE order_status = 'DELIVERED' ORDER BY total_amount DESC

    // ์ฃผ๋ฌธ ์ƒํƒœ(OrderStatus)๊ฐ€ 'CANCELED'์ด๊ณ , ์ฃผ๋ฌธ ๊ธˆ์•ก(totalAmount)์ด 100,000์› ์ด์ƒ์ธ ๋ชจ๋“  ์ฃผ๋ฌธ ์กฐํšŒ
    List<Order> findAllByOrderStatusAndTotalAmountGreaterThanEqual(OrderStatus orderStatus, BigDecimal totalAmount);
    // SELECT * FROM orders WHERE order_status = 'CANCELED' AND total_amount >= 100000

    // ์ฃผ๋ฌธ ์ƒํƒœ(OrderStatus)๊ฐ€ 'SHIPPED'์ด๊ฑฐ๋‚˜ 'DELIVERED'์ธ ๋ชจ๋“  ์ฃผ๋ฌธ ์กฐํšŒ
    List<Order> findAllByOrderStatusOrOrderStatus(OrderStatus orderStatus1, OrderStatus orderStatus2);
    // SELECT * FROM orders WHERE order_status = 'SHIPPED' OR order_status = 'DELIVERED'

    // ์ฃผ๋ฌธ ์ƒํƒœ(OrderStatus)๊ฐ€ 'PENDING'์ด ์•„๋‹Œ ๋ชจ๋“  ์ฃผ๋ฌธ ์กฐํšŒ
    List<Order> findAllByOrderStatusNot(OrderStatus orderStatus);
    // SELECT * FROM orders WHERE NOT order_status = 'PENDING'

    // ์ฃผ๋ฌธ ์ƒํƒœ(OrderStatus)๊ฐ€ 'OPEND'์ด๊ณ , ์ฃผ๋ฌธ ๊ธˆ์•ก(totalAmount)์ด 50,000์› ๋ฏธ๋งŒ์ธ ๋ชจ๋“  ์ฃผ๋ฌธ ์กฐํšŒ
    List<Order> findAllByOrderStatusAndTotalAmountLessThan(OrderStatus orderStatus, BigDecimal totalAmount);
    // SELECT * FROM orders WHERE order_status = 'OPEND' AND total_amount < 50000

    // ์ฃผ๋ฌธ ์ƒํƒœ(OrderStatus)๊ฐ€ 'COMPLETED'์ธ ์ฃผ๋ฌธ ์ค‘ ์ฃผ๋ฌธ ์ผ์‹œ(orderDatetime)๊ฐ€ ์˜ค๋Š˜ ๋‚ ์งœ๋ณด๋‹ค ์ด์ „์ธ ๋ชจ๋“  ์ฃผ๋ฌธ ์กฐํšŒ
    List<Order> findAllByOrderStatusAndOrderDatetimeBefore(OrderStatus orderStatus, LocalDateTime dateTime);
    // SELECT * FROM orders WHERE order_status = 'COMPLETED' AND order_datetime < '2023-07-28 12:00:00'
}
  • ๋ฉ”์„œ๋“œ ์ด๋ฆ„ ์ž์ฒด๋กœ ์ฟผ๋ฆฌ๋กœ ์‚ฌ์šฉํ•˜์—ฌ ๋ฐ์ดํ„ฐ๋ฅด ์กฐํšŒํ•˜๋Š” ๋ฐฉ๋ฒ•
  • ๋ณ„๋„์˜ JPQL ๋˜๋Š” ๋„ค์ดํ‹ฐ๋ธŒ SQL ์ฟผ๋ฆฌ๋ฅผ ์ž‘์„ฑํ•˜์ง€ ์•Š๊ณ ๋„ ๊ฐ„๋‹จํ•˜๊ฒŒ ๋ฐ์ดํ„ฐ๋ฅผ ์กฐํšŒ
  • ๋ฉ”์„œ๋“œ ์ด๋ฆ„์€ find, read, get, query, stream, count, exists ๋“ฑ์œผ๋กœ ์‹œ์ž‘ํ•œ๋‹ค.
  • By ํ‚ค์›Œ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๊ฒ€์ƒ‰ ์กฐ๊ฑด์„ ์ง€์ •
  • ๊ฒ€์ƒ‰ ์กฐ๊ฑด์—๋Š” ์—”ํ‹ฐํ‹ฐ์˜ ํ•„๋“œ ์ด๋ฆ„ ์‚ฌ์šฉ
  • ๊ฒ€์ƒ‰ ์กฐ๊ฑด์ด ์—ฌ๋Ÿฌ ๊ฐœ์ธ ๊ฒฝ์šฐ And ๋˜๋Š” Or ํ‚ค์›Œ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์กฐํ•ฉ
  • ์ •๋ ฌ ์กฐ๊ฑด์„ ์ถ”๊ฐ€ํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ, OrderBy ํ‚ค์›Œ๋“œ ์‚ฌ์šฉ

์ปค์Šคํ…€ ์ฟผ๋ฆฌ

public interface OrderRepository extends JpaRepository<Order, String> {
    // ์ฃผ๋ฌธ ์ƒํƒœ(OrderStatus)๊ฐ€ 'COMPLETED'์ด๊ณ , ์ฃผ๋ฌธ ๊ธˆ์•ก(totalAmount)์ด ํŠน์ • ๊ธˆ์•ก ์ด์ƒ์ด๋ฉด์„œ ์ฃผ๋ฌธ ๋ฉ”๋ชจ(memo)์— ํŠน์ • ๋‹จ์–ด๊ฐ€ ํฌํ•จ๋œ ์ฃผ๋ฌธ ์กฐํšŒ
    @Query("SELECT o FROM Order o WHERE o.orderStatus = 'COMPLETED' AND o.totalAmount >= :amount AND o.memo LIKE %:keyword%")
    List<Order> findCompletedOrdersByAmountAndMemoContaining(@Param("amount") BigDecimal amount, @Param("keyword") String keyword);

    // ํŠน์ • ์‚ฌ์šฉ์ž์˜ ์ฃผ๋ฌธ ์ค‘ ์ฃผ๋ฌธ ์ƒํƒœ(OrderStatus)๊ฐ€ 'PENDING'์ด๊ณ , ์ฃผ๋ฌธ ๊ธˆ์•ก(totalAmount)์ด ๊ฐ€์žฅ ๋†’์€ ์ฃผ๋ฌธ ์กฐํšŒ
    @Query("SELECT o FROM Order o WHERE o.user = :user AND o.orderStatus = 'PENDING' ORDER BY o.totalAmount DESC")
    Order findHighestAmountPendingOrderByUser(@Param("user") User user);

    // ํŠน์ • ์‚ฌ์šฉ์ž์˜ ์ฃผ๋ฌธ ์ค‘ ์ฃผ๋ฌธ ์ผ์‹œ(orderDatetime)๊ฐ€ ํŠน์ • ๋‚ ์งœ ์ดํ›„์ธ ์ฃผ๋ฌธ ์กฐํšŒ
    @Query("SELECT o FROM Order o WHERE o.user = :user AND o.orderDatetime >= :date")
    List<Order> findOrdersByUserAndOrderDatetimeAfter(@Param("user") User user, @Param("date") LocalDateTime date);

    // ํŠน์ • ์ƒํ’ˆ(product)๊ณผ ๊ด€๋ จ๋œ ๋ชจ๋“  ์ฃผ๋ฌธ ์กฐํšŒ
    @Query("SELECT o FROM Order o JOIN o.orderItems oi WHERE oi.product = :product")
    List<Order> findOrdersByProduct(@Param("product") Product product);

    // ํŠน์ • ์‚ฌ์šฉ์ž์˜ ์ฃผ๋ฌธ ์ค‘ ์ฃผ๋ฌธ ์ƒํƒœ(OrderStatus)๊ฐ€ 'CANCELED'์ด๊ณ , ์ฃผ๋ฌธ ๊ธˆ์•ก(totalAmount)์ด ํŠน์ • ๊ธˆ์•ก ์ดํ•˜์ธ ์ฃผ๋ฌธ ์กฐํšŒ
    @Query("SELECT o FROM Order o WHERE o.user = :user AND o.orderStatus = 'CANCELED' AND o.totalAmount <= :amount")
    List<Order> findCanceledOrdersByUserAndAmountLessThanOrEqual(@Param("user") User user, @Param("amount") BigDecimal amount);

    // ํŠน์ • ์‚ฌ์šฉ์ž์˜ ์ฃผ๋ฌธ ์ค‘ ์ฃผ๋ฌธ ์ƒํƒœ(OrderStatus)๊ฐ€ 'DELIVERED'์ด๊ณ , ์ฃผ๋ฌธ ์ผ์‹œ(orderDatetime)๊ฐ€ ํŠน์ • ๊ธฐ๊ฐ„ ๋‚ด์— ์žˆ๋Š” ์ฃผ๋ฌธ ์กฐํšŒ
    @Query("SELECT o FROM Order o WHERE o.user = :user AND o.orderStatus = 'DELIVERED' AND o.orderDatetime BETWEEN :startDate AND :endDate")
    List<Order> findDeliveredOrdersByUserAndOrderDatetimeBetween(@Param("user") User user, @Param("startDate") LocalDateTime startDate, @Param("endDate") LocalDateTime endDate);
}
  • ์œ„์— ๋ฉ”์„œ๋“œ ์ฟผ๋ฆฌ ๋ฐฉ๋ฒ•์œผ๋กœ ํ•  ์ˆ˜ ์—†๋Š” ๋ณต์žกํ•œ ์กฐํšŒ๋‚˜ ์ˆ˜์ • ์ž‘์—…์€ ์ง์ ‘ @Query๋ฅผ ํ†ตํ•ด JPQL ๋˜๋Š” ๋„ค์ดํ‹ฐ๋ธŒ SQL ์ฟผ๋ฆฌ๋ฅผ ์ž‘์„ฑํ•ด์„œ ์‹คํ–‰
    • ์กฐ์ธ์„ ์‚ฌ์šฉํ•˜๋Š” ๋ณต์žกํ•œ ์กฐํšŒ
    • ์ง‘๊ณ„ ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ์กฐํšŒ
    • ๋™์  ์ฟผ๋ฆฌ
    • ์—ฌ๋Ÿฌ ํ…Œ์ด๋ธ”์„ ํ•œ๋ฒˆ์— ์ˆ˜์ •ํ•ด์•ผ ํ•˜๋Š” ๋ณต์žกํ•œ ์ˆ˜์ • ์ž‘์—…

QueryDSL

// QUser ํด๋ž˜์Šค๋Š” QueryDSL์—์„œ ์‚ฌ์šฉํ•  ์‚ฌ์šฉ์ž ์—”ํ‹ฐํ‹ฐ์˜ ๋ณ„์นญ
QUser qUser = QUser.user;

// ์‚ฌ์šฉ์ž ์ด๋ฆ„์ด 'John'์ธ ์‚ฌ์šฉ์ž ์กฐํšŒ
User user = new JPAQueryFactory(entityManager)
            .selectFrom(qUser)
            .where(qUser.name.eq("John"))
            .fetchOne();

// ๋‚˜์ด๊ฐ€ 20 ์ด์ƒ์ธ ์‚ฌ์šฉ์ž๋“ค ์กฐํšŒ
List<User> users = new JPAQueryFactory(entityManager)
            .selectFrom(qUser)
            .where(qUser.age.goe(20))
            .fetch();

// ์‚ฌ์šฉ์ž์˜ ์ด๋ฆ„๊ณผ ์ด๋ฉ”์ผ ์ฃผ์†Œ๋งŒ ์กฐํšŒํ•˜์—ฌ ํŠœํ”Œ ๋ฆฌ์ŠคํŠธ๋กœ ๋ฐ˜ํ™˜
List<Tuple> userTupleList = new JPAQueryFactory(entityManager)
            .select(qUser.name, qUser.email)
            .from(qUser)
            .fetch();

// ํŠน์ • ์ปฌ๋Ÿผ์˜ ๊ฐ’์„ ๊ทธ๋ฃนํ™”ํ•˜์—ฌ ์ง‘๊ณ„ ํ•จ์ˆ˜ ์ ์šฉ
List<Tuple> aggregatedData = new JPAQueryFactory(entityManager)
            .select(qUser.age.avg(), qUser.age.max(), qUser.age.min())
            .from(qUser)
            .groupBy(qUser.gender)
            .fetch();
  • ๊ณต์‹ ๋ฌธ์„œ
  • ๋นŒ๋” ํŒจํ„ด ๋ฐฉ์‹์œผ๋กœ ์ฟผ๋ฆฌ๋ฅผ ์ƒ์„ฑํ•˜์—ฌ SQL๊ณผ JPQL์„ ์‰ฝ๊ฒŒ ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ๋„๋ก ์ง€์›ํ•˜๋Š” ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ
  • JPA์™€ ํ•จ๊ป˜ ์‚ฌ์šฉ๋˜๋ฉฐ, ๋ณต์žกํ•œ ์ฟผ๋ฆฌ๋ฅผ ์ž๋ฐ” ์ฝ”๋“œ๋กœ ๊ฐ„ํŽธํ•˜๊ฒŒ ์ž‘์„ฑ ๊ฐ€๋Šฅ
  • ๋™์  ์ฟผ๋ฆฌ๋ฅผ ์‰ฝ๊ฒŒ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ์Œ
profile
์›น ๊ฐœ๋ฐœ์— ๊ด€์‹ฌ ์žˆ์Šต๋‹ˆ๋‹ค.

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