๐ช JPA ๊ด๋ จ ์ฉ์ด ์ ๋ฆฌ
JPA๋ DB์ ๊ฐ์ฒด๋ฅผ ๋งคํํ๋ ๊ธฐ์ ์ผ ๋ฟ, ๋ด๋ถ์ ์ผ๋ก DB์ ํต์ ์ ์ํด์๋ JDBC๋ฅผ ํ์๋ก ํ๊ฒ๋๋ค.
๋ํ JPA๋ JDBC์ ๋ง์ฐฌ๊ฐ์ง๋ก ์ธํฐํ์ด์ค์ด๊ธฐ ๋๋ฌธ์ ๊ตฌํ์ฒด๊ฐ ํ์ํ๊ณ , ๊ทธ ๊ตฌํ์ฒด ์ค ํ๋๊ฐ Hibernate์ด๋ค.
N+1 ๋ฌธ์ ๋ ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ์ ํ๋ฆฌ์ผ์ด์
๊ฐ์ ๋นํจ์จ์ ์ธ ์ฟผ๋ฆฌ ์คํ์ผ๋ก ์ธํด ๋ฐ์ํ๋ ์ฑ๋ฅ ๋ฌธ์ ๋ฅผ ์ง์นญํฉ๋๋ค.
์ด๋ ์ฃผ๋ก ORM(Object-Relational Mapping) ๊ธฐ์ (JPA, Hibernate ๋ฑ)์ ์ฌ์ฉํ ๋ ๋ฐ์ํ๋ฉฐ, ํ ๋ฒ์ ๋ฐ์ดํฐ๋ฒ ์ด์ค ์กฐํ๋ก ํด๊ฒฐํ ์ ์๋ ์์
์ ๋ํด ์ถ๊ฐ์ ์ธ N๊ฐ์ ์ฟผ๋ฆฌ๊ฐ ์คํ๋๋ ์ํฉ์ ์๋ฏธํฉ๋๋ค.
N+1 ๋ฌธ์ ๋ ์ฃผ๋ก ์ง์ฐ ๋ก๋ฉ(Lazy Loading)์ผ๋ก ์ธํด ๋ฐ์ํฉ๋๋ค.
์ง์ฐ ๋ก๋ฉ์ ๊ด๋ จ ์ํฐํฐ๋ฅผ ํ์ํ ๋๋ง ๋ก๋ฉํ๋ ๋ฐฉ์์ผ๋ก, ๊ธฐ๋ณธ์ ์ผ๋ก ํจ์จ์ ์ธ ๋ฐฉ๋ฒ์ด์ง๋ง ์๋์ ๊ฐ์ ์ํฉ์์ ๋ฌธ์ ๊ฐ ๋ฐ์ํฉ๋๋ค.
๋ ๊ฐ์ ์ํฐํฐ ๊ฐ ๊ด๊ณ:
๋ฌธ์ ๋ฐ์ ๊ณผ์ :
List<Parent> parents = entityManager.createQuery("SELECT p FROM Parent p", Parent.class).getResultList();
// ๊ฐ Parent ์ํฐํฐ์ ์์ ์ํฐํฐ๋ฅผ ๋ก๋ (์ง์ฐ ๋ก๋ฉ)
for (Parent parent : parents) {
System.out.println(parent.getChildren().size()); // ์์ ์ํฐํฐ ์กฐํ ์ฟผ๋ฆฌ ๋ฐ์
}
SELECT * FROM Parent;
โ ๋ถ๋ชจ ์ํฐํฐ๋ฅผ ์กฐํํ๋ ์ฟผ๋ฆฌ 1๋ฒ ์คํ.SELECT * FROM Child WHERE parent_id = ?;
โ ๊ฐ ๋ถ๋ชจ ์ํฐํฐ๋ง๋ค ์์ ๋ฐ์ดํฐ๋ฅผ ์กฐํํ๋ ์ฟผ๋ฆฌ N๋ฒ ์คํ.JOIN
์ ์ฌ์ฉํด ๊ด๋ จ๋ ์ํฐํฐ๋ฅผ ํ ๋ฒ์ ์ฟผ๋ฆฌ๋ก ๋ก๋ํ๋ ๋ฐฉ์์
๋๋ค.String jpql = "SELECT p FROM Parent p JOIN FETCH p.children";
List<Parent> parents = entityManager.createQuery(jpql, Parent.class).getResultList();
JOIN FETCH
๋ฅผ ์ฌ์ฉํ๋ฉด ๋ถ๋ชจ์ ์์ ์ํฐํฐ๋ฅผ ํ ๋ฒ์ ๊ฐ์ ธ์ต๋๋ค.@Entity
@NamedEntityGraph(
name = "Parent.withChildren",
attributeNodes = @NamedAttributeNode("children")
)
public class Parent { ... }
// ์ฌ์ฉ ์
EntityGraph<?> entityGraph = em.getEntityGraph("Parent.withChildren");
List<Parent> parents = em.createQuery("SELECT p FROM Parent p", Parent.class)
.setHint("javax.persistence.fetchgraph", entityGraph)
.getResultList();
String jpql = "SELECT new com.example.dto.ParentChildDTO(p.name, c.name) " +
"FROM Parent p JOIN p.children c";
List<ParentChildDTO> dtos = entityManager.createQuery(jpql, ParentChildDTO.class).getResultList();