ํ๋ก์
Member ๋ฅผ ์กฐํํ ๋ Team ๋ ํจ๊ป ์กฐํํด์ผ ํ ๊น?
Member ๋ฅผ ์กฐํํด์ username ๋ง ์ฌ์ฉํ ๊ฑด๋ฐ, Team ๊น์ง ๊ฐ์ด ์กฐํํด์ค๋ฉด ์ํด๊ฐ ์๋๊น?
์ด๋ฅผ ์ต์ ํํ๊ธฐ ์ํด JPA ์์ ํ๋ก์์ ์ง์ฐ ๋ก๋ฉ์ ์ฌ์ฉํ๋ค.
ํ๋ก์ ๊ธฐ์ด
em.find()
๋ DB ๋ฅผ ํตํด์ ์ค์ ์ํฐํฐ ๊ฐ์ฒด๋ฅผ ์กฐํํ๋ ๋ฐ๋ฉด, em.getReference()
๋ DB ์กฐํ๋ฅผ ๋ฏธ๋ฃจ๋ ๊ฐ์ง(ํ๋ก์) ์ํฐํฐ ๊ฐ์ฒด๋ฅผ ์กฐํํ๋ค.
์ค์ ๋ก em.find(Member.class, member.getId())
๋ฅผ ํตํด member ๋ฅผ ์กฐํํ๋ฉด SELECT ์ฟผ๋ฆฌ๊ฐ ๋ ์๊ฐ์ง๋ง, em.getReference(Member.class, member.getId())
๋ฅผ ํตํด member ๋ฅผ ์กฐํํ๋ฉด SELECT ์ฟผ๋ฆฌ๊ฐ ๋ ์๊ฐ์ง ์๋๋ค.
ํ ํธ, Member findMember = em.getReference(Member.class, member.getId())
๋ก ์กฐํํ ํ findMember.getUsername()
์ ํธ์ถํ ๊ฒฝ์ฐ ๊ทธ์ ์์ผ SELECT ์ฟผ๋ฆฌ๊ฐ ๋ ์๊ฐ๋ ๊ฒ์ ํ์ธํ ์ ์๋ค.
ํ๋ก์ ํน์ง
ํ๋ก์๋ ์ค์ ํด๋์ค๋ฅผ ์์ ๋ฐ์์ ๋ง๋ค์ด์ง๊ธฐ ๋๋ฌธ์ ์ค์ ํด๋์ค์ ๊ฒ ๋ชจ์ต์ด ๊ฐ๋ค.
์ด๋ก ์ ์ฌ์ฉํ๋ ์
์ฅ์์ ์ง์ง ๊ฐ์ฒด์ธ์ง ํ๋ก์ ๊ฐ์ฒด์ธ์ง ๊ตฌ๋ถํ์ง ์๊ณ ์ฌ์ฉํ๋ฉด๋๋ค.
ํ๋ก์ ๊ฐ์ฒด๋ ์ค๊ฒ ๊ฐ์ฒด์ ์ฐธ์กฐ(target)๋ฅผ ๋ณด๊ดํ๊ธฐ ๋๋ฌธ์ ํ๋ก์ ๊ฐ์ฒด๋ฅผ ํธ์ถํ๋ฉด ํ๋ก์ ๊ฐ์ฒด๋ ์ค์ ๊ฐ์ฒด์ ๋ฉ์๋๋ฅผ ํธ์ถํ๋ค.
ํ๋ก์ ๊ฐ์ฒด์ ์ด๊ธฐํ
Member member = em.getReference(Member.class, "id1");
member.getName();
ํ๋ก์์ ํน์ง
ํ๋ก์ ๊ฐ์ฒด๋ ์ฒ์ ์ฌ์ฉํ ๋ ํ ๋ฒ๋ง ์ด๊ธฐํํ๋ค.
ํ๋ก์ ๊ฐ์ฒด๊ฐ ์ด๊ธฐํ๋๋ฉด ํ๋ก์ ๊ฐ์ฒด๋ฅผ ํตํด์ ์ค์ ์ํฐํฐ์ ์ ๊ทผ์ด ๊ฐ๋ฅํด์ง๋ ๊ฒ์ด์ง, ํ๋ก์ ๊ฐ์ฒด๋ฅผ ์ด๊ธฐํ ํ ๋, ํ๋ก์ ๊ฐ์ฒด๊ฐ ์ค์ ์ํฐํฐ๋ก ๋ฐ๋๋ ๊ฒ์ด ์๋๋ค.
ํ๋ก์ ๊ฐ์ฒด๋ ์๋ณธ ์ํฐํฐ๋ฅผ ์์๋ฐ๊ธฐ ๋๋ฌธ์ ํ์
์ฒดํฌ ์ ์ฃผ์ํด์ผ ํ๋ค.
==
๋น๊ต ๋์ ์ instance of
๋ฅผ ์ฌ์ฉํด์ผ ํ๋ค.
์์์ฑ ์ปจํ
์คํธ์ ์ฐพ๊ณ ์ ํ๋ ์ํฐํฐ๊ฐ ์ด๋ฏธ em.find()
๋ฅผ ํตํด ์กด์ฌํ๋ค๋ฉด em.getReference()
๋ฅผ ํธ์ถํด๋ ์ค์ ์ํฐํฐ๋ฅผ ๋ฐํํ๋ค. ๋ฐ๋๋ก, em.getReference()
๋ก ๋จผ์ ์ํฐํฐ๋ฅผ ์กฐํํ๊ณ em.find()
๋ก ๊ฐ์ ์ํฐํฐ๋ฅผ ์ฐพ๋๋ค๋ฉด, em.find()
๋ก ๋ฐํ๋ ์ํฐํฐ๋ ํ๋ก์ ๊ฐ์ฒด์์ ์ ์ ์๋ค.
์์์ฑ ์ปจํ
์คํธ์ ๋์์ ๋ฐ์ ์ ์๋ ์ค์์ ์ํ์ผ ๋, ํ๋ก์๋ฅผ ์ด๊ธฐํํ๋ฉด ๋ฌธ์ ๊ฐ ๋ฐ์ํ๋ค.
Hibernate ์ ๊ฒฝ์ฐ LazyInitializationException
์์ธ๋ฅผ ํฐํธ๋ฆฐ๋ค.
ํ๋ก์ ํ์ธ
emf.getPersistenceUnitUtil().isLoaded(refMember)
๋ฅผ ํตํด ํ๋ก์ ์ธ์คํด์ค์ ์ด๊ธฐํ ์ฌ๋ถ๋ฅผ ํ์ธํ ์ ์๋ค.
refMember.getClass()
๋ฅผ ํตํด ํ๋ก์ ํด๋์ค๋ฅผ ํ์ธํ ์ ์๋ค.
Hibernate.initialize(refMember)
๋ฅผ ํตํด ํ๋ก์๋ฅผ ๊ฐ์ ๋ก ์ด๊ธฐํ ํ ์ ์๋ค.
JPA ์๋ ๊ฐ์ ์ด๊ธฐํ๊ฐ ์๊ธฐ ๋๋ฌธ์ ๊ทธ๋ฅ refMember.getName()
์ผ๋ก ๊ฐ์ ์ด๊ธฐํ ํด๋ ๋๋ค.
์ฆ์ ๋ก๋ฉ๊ณผ ์ง์ฐ ๋ก๋ฉ
์ง์ฐ ๋ก๋ฉ LAZY ๋ฅผ ์ฌ์ฉํด์ ํ๋ก์๋ก ์กฐํ
@Entity
public class Member {
@Id @GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(name = "name")
private String name;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "team_id")
private Team team;
}
Member member = em.find(Member.class, 1L);
Team team = member.getTeam();
team.getName(); // ์ค์ team ์ ์ฌ์ฉํ๋ ์์ ์ ์ด๊ธฐํ
Member ์ Team ์ ์์ฃผ ํจ๊ป ์ฌ์ฉํ๋ค๋ฉด? EAGER ์ฌ์ฉ
Member member = em.find(Member.class, 1L); // ์ด ์์ ์ team ๋ ํจ๊ป ์กฐํ
Team team = member.getTeam();
team.getName();
ํ๋ก์์ ์ฆ์๋ก๋ฉ ์ฃผ์
๊ฐ๊ธ์ ์ด๋ฉด ์ง์ฐ ๋ก๋ฉ๋ง ์ฌ์ฉํ๋ค. ํนํ ์ค๋ฌด์์ ์ฆ์ ๋ก๋ฉ์ ๊ฑฐ์ ์ฌ์ฉํ์ง ์๋๋ค. ์ฆ์ ๋ก๋ฉ์ ์ ์ฉํ๋ฉด ์ ํ ์์ํ์ง ๋ชปํ SQL ์ด ๋ ์๊ฐ๋ค. ๋ํ, ์ฆ์ ๋ก๋ฉ์ JPQL ์์ N + 1 ๋ฌธ์ ๋ฅผ ์ผ์ผํจ๋ค. N + 1 ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ๊ธฐ ์ํด, ์ค๋ฌด์์๋ LAZY ๋ก ๋ค ๋ฐ๋ฅด๊ณ , A, B, C ๋ฅผ ํ๋ฒ์ ์กฐํํด์ผ ํ ๊ฒฝ์ฐ fetch join ์ผ๋ก ํ ๋ฐฉ์ ๊ฐ์ ธ์ค๋ ๋ฐฉ๋ฒ์ ์ฃผ๋ก ์ฌ์ฉํ๋ค.
์ง์ฐ ๋ก๋ฉ ํ์ฉ
Member
์ Team
์ ์์ฃผ ํจ๊ป ์ฌ์ฉ โ ์ฆ์ ๋ก๋ฉ
Member
์ Order
๋ ๊ฐ๋ ์ฌ์ฉ โ ์ง์ฐ ๋ก๋ฉ
Order
์ Product
๋ ์์ฃผ ํจ๊ป ์ฌ์ฉ โ ์ฆ์ ๋ก๋ฉ
์ง์ฐ ๋ก๋ฉ ํ์ฉ - ์ค๋ฌด
- ๋ชจ๋ ์ฐ๊ด๊ด๊ณ์ ์ง์ฐ ๋ก๋ฉ์ ์ฌ์ฉํด๋ผ!
- ์ค๋ฌด์์ ์ฆ์ ๋ก๋ฉ์ ์ฌ์ฉํ์ง ๋ง๋ผ!
- JPQL fetch join ์ด๋, ์ํฐํฐ ๊ทธ๋ํ ๊ธฐ๋ฅ์ ์ฌ์ฉํด๋ผ!
์์์ฑ ์ ์ด(CASCADE)์ ๊ณ ์ ๊ฐ์ฒด
์์์ฑ ์ ์ด CASCADE
@Entity
public class Parent {
@Id
@GeneratedValue
private Long id;
private String name;
@OneToMany(mappedBy = "parent", cascade = CascadeType.ALL)
private List<Child> childList = new ArrayList<>();
}
@Entity
public class Child {
@Id
@GeneratedValue
private Long id;
private String name;
@ManyToOne
@JoinColumn(name = "parent_id")
private Parent parent;
}
ํน์ ์ํฐํฐ๋ฅผ ์์ ์ํ๋ก ๋ง๋ค ๋ ์ฐ๊ด๋ ์ํฐํฐ๋ ํจ๊ป ์์ ์ํ๋ก ๋ง๋ค๊ณ ์ถ์ ๋ ์ฌ์ฉํ๋ค.
Child child1 = new Child();
Child child2 = new Child();
Parent parent = new Parent();
parent.addChild(child1);
parent.addChild(child2);
em.persist(parent);
// cascade ์ ์ฉ ์ ์๋ ์ฝ๋๋ฅผ ์ ์ ๊ฒ๊ณผ ๊ฐ์ ํจ๊ณผ๋ฅผ ์ป์ ์ ์๋ค.
// em.persist(child1);
// em.persist(child2);
์ฃผ์
์์์ฑ ์ ์ด๋ ์ฐ๊ด๊ด๊ณ๋ฅผ ๋งคํํ๋ ๊ฒ๊ณผ ์๋ฌด ๊ด๋ จ์ด ์๋ค. ์ํฐํฐ๋ฅผ ์์ํํ ๋ ์ฐ๊ด๋ ์ํฐํฐ๋ ํจ๊ป ์์ํํ๋ ํธ๋ฆฌํจ๋ง์ ์ ๊ณตํ ๋ฟ์ด๋ค.
CASCADE ์ ์ข ๋ฅ
ALL
๋ชจ๋ ์ ์ฉ - Life Cycle ์ ๋ง์ถฐ์ผํ ๋PERSIST
์์ - ๊ฐ์ด ์ญ์ ๋๋ ๊ฒฝ์ฐ๊ฐ ์ํํ ๋
๊ณ ์ ๊ฐ์ฒด
๊ณ ์ ๊ฐ์ฒด ์ ๊ฑฐ - ๋ถ๋ชจ ์ํฐํฐ์ ์ฐ๊ด ๊ด๊ณ๊ฐ ๋์ด์ง ์์ ์ํฐํฐ๋ฅผ ์๋์ผ๋ก ์ญ์ ํ๋ ๊ฒ์ด๋ค.
orphanRemoval = true
์ค์ ์ ์ฃผ์ด ์ฌ์ฉํ ์ ์๋ค.
Parent parent = em.find(Parent.class, id);
parent.getChildren().remove(0);
// ์ฐ๊ด๊ด๊ณ๊ฐ ๋์ด์ง๋ฉด DELETE ์ฟผ๋ฆฌ๊ฐ ๋ ์๊ฐ
๊ณ ์ ๊ฐ์ฒด - ์ฃผ์
์ฐธ์กฐ๊ฐ ์ ๊ฑฐ๋ ์ํฐํฐ๋ ๋ค๋ฅธ ๊ณณ์์ ์ฐธ์กฐํ์ง ์๋ ๊ณ ์ ๊ฐ์ฒด๋ก ๋ณด๊ณ ์ญ์ ํ๋ ๊ธฐ๋ฅ์ด๋ค.
๋ฐ๋ผ์, ์ฐธ์กฐํ๋ ๊ณณ์ด ํ๋์ผ ๋ ์ฌ์ฉํด์ผ ํ๋ฉฐ ํน์ ์ํฐํฐ๊ฐ ๊ฐ์ธ ์์ ํ ๋ ์ฌ์ฉํด์ผ ํ๋ค.
@OneToOne
@OneToMany
์์๋ง ์ฌ์ฉ ๊ฐ๋ฅํ๋ค.
orphanRemoval = true
์ ์ฌ์ฉํ๋ฉด ๋ถ๋ชจ๋ฅผ ์ ๊ฑฐํ ๋ ์์๋ ํจ๊ป ์ ๊ฑฐ๋๋ค.
์์์ฑ ์ ์ด + ๊ณ ์ ๊ฐ์ฒด, ์๋ช ์ฃผ๊ธฐ
์ค์ค๋ก ์๋ช
์ฃผ๊ธฐ๋ฅผ ๊ด๋ฆฌํ๋ ์ํฐํฐ๋ em.persist()
๋ก ์์ํ ํน์ em.remove()
๋ก ์ ๊ฑฐํ ์ ์๋ค.
CascadeType.ALL
orphanRemovel=true
๋ชจ๋ ํ์ฑํํ๋ค๋ฉด ๋ถ๋ชจ ์ํฐํฐ๋ฅผ ํตํด์ ์์์ ์๋ช
์ฃผ๊ธฐ๋ฅผ ๊ด๋ฆฌํ ์ ์๋ค.
์ค์ ์์ 5 - ์ฐ๊ด๊ด๊ณ ๊ด๋ฆฌ
๊ธ๋ก๋ฒ ํ์น ์ ๋ต ์ค์
๋ชจ๋ ์ฐ๊ด๊ด๊ณ๋ฅผ ์ง์ฐ ๋ก๋ฉ์ผ๋ก ์ค์ ํ๋ค.
์์์ฑ ์ ์ด ์ค์
Order
โ Delivery
๋ฅผ ์์์ฑ ์ ์ด ALL ๋ก ์ค์ ํ๋ค.
Order
โ OrderItem
์ ์์์ฑ ์ ์ด ALL ๋ก ์ค์ ํ๋ค.