Optional Eager - redutan/redutan.github.io GitHub Wiki

Prolog

JPA ์—ฐ๊ด€๊ด€๊ณ„ ๊ธฐ๋ณธ ๋กœ๋”ฉ ์ „๋žต

  • OneToOne(child) : EAGER
  • OneToOne(parent) : LAZY
  • OneToMany : LAZY
  • ManyToOne : EAGER

// FIXME ์œ„ ๋‚ด์šฉ์ด ๋งž๋Š”์ง€ ํ™•์ธ์š”๋ง

ํ•˜์ง€๋งŒ..

๋ชจ๋“  ๋กœ๋”ฉ ์ „๋žต์€ LAZY๋กœ ์„ค์ •ํ•˜๊ณ , ํ•„์š”์— ๋”ฐ๋ผ์„œ EAGER ์„ค์ •์„ ํ•˜๋Š” ๊ฒƒ์ด ๋‚˜์€ ๊ฒƒ ๊ฐ™๋‹ค.

Eager by QueryDsl

  • fetchJoin()์„ ์ด์šฉํ•˜๋ฉด ๋จ
  • querydsl version : 4.1.4 ๊ธฐ์ค€

NoticeRepositoryImpl.java

public NoticeRepositoryImpl extends BaseRepositorySupport implements NoticeCustomRepository {
    // ...
    public Page<NoticeListDetail> findListDetails(Predicate predicate, Pageable pageable) {
        QNotice notice = QNotice.notice;
        QPartner partner = QPartner.partner;

        JPQLQuery<NoticeListDetail> innerQuery = from(notice)
                .innerJoin(notice.partner, partner)
                .fetchJoin()    // EAGER ๋กœ๋”ฉ
                .where(predicate)
                .select(new QNoticeListDetail(notice, partner));
        return queryToPage(innerQuery, pageable);
    }

๋งŒ์•ฝ ๋ชจ๋“  join์— ๋Œ€ํ•ด์„œ ์ฆ‰์‹œ๋กœ๋”ฉ ์ „๋žต์„ ์ทจํ•˜๊ณ  ์‹ถ์œผ๋ฉด fetchAll() ์—ฐ์‚ฐ์ž๋ฅผ ์‚ฌ์šฉ

BaseRepositorySupport.java

/**
 * ๊ณตํ†ต ์ €์žฅ์†Œ ์„œํฌํŠธ
 * ์ƒ์†์„ ํ†ตํ•ด์„œ ๊ณตํ†ต์ฝ”๋“œ๋ฅผ ๊ด€๋ฆฌ
 *
 * @author myeongju.jung
 */
public abstract class BaseRepositorySupport extends QueryDslRepositorySupport {
    public BaseRepositorySupport(Class<?> domainClass) {
        super(domainClass);
    }
    /**
     * ์ผ๋ฐ˜ JPQLQuery๋ฅผ Page๋กœ ๋ณ€ํ™˜
     *
     * @param query    ๋‚ด๋ถ€ JPQLQuery
     * @param pageable ํŽ˜์ด์ง• ์ธ์ž
     * @param <T>      ๋ฐ˜ํ™˜ ํƒ€์ž…
     * @return ํŽ˜์ด์ง• ๊ฒฐ๊ณผ
     */
    protected final <T> Page<T> queryToPage(JPQLQuery<T> query, Pageable pageable) {
        long count = query.fetchCount();

        List<T> content = Collections.emptyList();
        if (count > 0) {
            content = getQuerydsl().applyPagination(pageable, query).fetch();
        }
        return new PageImpl<>(content, pageable, count);
    }
}

Eager by spring-data-jpa

AdRepository.java

public interface AdRepository extends JpaRepository<Ad, Long>, QueryDslPredicateExecutor<Ad> {
    @EntityGraph("Ad.withCompany")
    Page<Ad> findAll(Predicate predicate, Pageable pageable);
}

Ad.java

@Entity
@NamedEntityGraph(name = "Ad.withCompany", attributeNodes = @NamedAttributeNode("company"))
// ...
public class Ad {
    @Id
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "AD_SEQ")
    @Column(name = "AD_NO")
    private Long adNo;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "COMPANY_NO", nullable = false, updatable = false,
            foreignKey = @ForeignKey(name = "FK_AD_COMPANY_NO"))
    private Company company;
    // ...
}
  • @EntityGraph("Ad.withCompany") ๋•Œ๋ฌธ์— ๋ฐ”๋กœ ad์™€ company๊ฐ€ join(EAGER) ๋˜์–ด ์กฐํšŒ๋œ๋‹ค.
  • @EntityGraph์—์„œ ์—ฐ๊ด€๊ด€๊ณ„ ๋กœ๋”ฉ ์ „๋žต์„ ์ง์ ‘ ์„ค์ •ํ•˜๊ธฐ ๋ณด๋‹ค๋Š” ํ•ด๋‹น Entity์—์„œ @NamedEntityGraph๋กœ ์„ ์–ธํ•œ ๊ฒƒ์„ ๊ฐ€์ ธ๋‹ค ์“ฐ๋Š” ๊ฒƒ์„ ์ถ”์ฒœ
    • ๋Œ€๋ถ€๋ถ„์˜ ๊ฒฝ์šฐ ์žฌ์‚ฌ์šฉํ•˜๊ฒŒ ๋˜๋Š” ๊ฒฝ์šฐ๊ฐ€ ๋งŽ์œผ๋ฉฐ, ์—ฐ๊ด€๊ด€๊ณ„์— ๋Œ€ํ•œ ๋กœ๋”ฉ ์ „๋žต์„ Entity์—์„œ ๊ด€๋ฆฌํ•  ์ˆ˜ ์žˆ๋‹ค.

์—ฐ๊ด€๊ด€๊ณ„์˜ ์—ฐ๊ด€๊ด€๊ณ„๊นŒ์ง€ ์ฆ‰์‹œ ๋กœ๋”ฉ

Partner, Company and Ad

  • ๋งŒ์•ฝ ์œ„์™€ ๊ฐ™์€ ๋„๋ฉ”์ธ ๋ชจ๋ธ ์ƒํ™ฉ์—์„œ Ad ๋ชฉ๋ก์„ ์กฐํšŒํ•  ์‹œ Company ๋ฟ๋งŒ ์•„๋‹ˆ๋ผ Partner๊นŒ์ง€ ์ฆ‰์‹œ(EAGER) ๋กœ๋”ฉํ• ๋ ค๋ฉด?

AdRepository.java

public interface AdRepository extends JpaRepository<Ad, Long>, QueryDslPredicateExecutor<Ad> {
    @EntityGraph("Ad.withCompanyAndPartner")
    Page<Ad> findAll(Predicate predicate, Pageable pageable);
}

Ad.java

@Entity
@NamedEntityGraph(name = "Ad.withCompanyAndPartner",
        attributeNodes = @NamedAttributeNode(value = "company", subgraph = "companyWithPartner"),
        subgraphs = @NamedSubgraph(name = "companyWithPartner", attributeNodes = @NamedAttributeNode("partner")))
// ...
public class Ad {
    @Id
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "AD_SEQ")
    @Column(name = "AD_NO")
    private Long adNo;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "COMPANY_NO", nullable = false, updatable = false,
            foreignKey = @ForeignKey(name = "FK_AD_COMPANY_NO"))
    private Company company;
    // ...
}
  • @NamedEntityGraph ์„ค์ •์ด ํ•ต์‹ฌ. ํ•ด๋‹น ๋ถ€๋ถ„์—์„œ Ad -> Company -> Partner ๊นŒ์ง€ ๊ฐ์ฒด๊ทธ๋ž˜ํ”„ ์„ค์ •

Eager By hibernate

// TODO

PlantUml

Partner, Company and Ad

@startuml
class Partner {
}
class Company {
  -partner:Partner
  -ads:List<Ad>
}
class Ad {
  -company:Company
}
Partner <-- "*" Company
Company <--> "*" Ad
@enduml
โš ๏ธ **GitHub.com Fallback** โš ๏ธ