๐ŸŒ WEB/JPA

7. ์ž๋ฐ” ORM ํ‘œ์ค€ JPA ํ”„๋กœ๊ทธ๋ž˜๋ฐ - ํ”„๋ก์‹œ์™€ ์—ฐ๊ด€๊ด€๊ณ„ ๊ด€๋ฆฌ

์• ์ •์“ฐ 2021. 5. 18. 17:54

ํ”„๋ก์‹œ

Team์— ์†ํ•ด์žˆ๋Š” Member ๋ฅผ ์กฐํšŒํ•  ์‹œ Team๊นŒ์ง€ ์กฐํšŒํ•  ํ•„์š”๊ฐ€ ์žˆ์„๊นŒ?

๋น„์ง€๋‹ˆ์Šค ๋กœ์ง์—์„œ ํ•„์š”ํ•˜์ง€ ์•Š์„ ๋•Œ๊ฐ€ ์žˆ๋Š”๋ฐ ํ•ญ์ƒ Team์„ ํ•จ๊ป˜ ์กฐํšŒํ•œ๋‹ค๋ฉด ๋‚ญ๋น„๊ฐ€ ๋ฐœ์ƒ๋œ๋‹ค.

์ด ๋‚ญ๋น„๋ฅผ ํ•˜์ง€ ์•Š๊ธฐ ์œ„ํ•ด ํ”„๋ก์‹œ๋ผ๋Š” ๊ฐ ๋ฉฐ์œผ๋กœ ํ•ด๊ฒฐํ•œ๋‹ค.

 

 

- ์‹ค์ œ ํด๋ž˜์Šค๋ฅผ ์ƒ์† ๋ฐ›์•„์„œ ๋งŒ๋“ค์–ด์ง€๊ธฐ ๋•Œ๋ฌธ์— ๊ฒ‰ ๋ชจ์–‘์ด ๊ฐ™๋‹ค

- ์‚ฌ์šฉํ•˜๋Š” ์ž…์žฅ์—์„œ๋Š” ์ง„์งœ, ๊ฐ€์งœ ๊ฐ์ฒด์ธ์ง€ ๊ตฌ๋ถ„ํ•˜์ง€ ์•Š๊ณ  ์‚ฌ์šฉํ•˜๋ฉด ๋œ๋‹ค.

- ํ”„๋ก์‹œ ๊ฐ์ฒด๋Š” ์‹ค์ œ ๊ฐ์ฒด์˜ ์ฐธ์กฐ๋ฅผ ๋ณด๊ด€ -> ํ”„๋ก์‹œ ๊ฐ์ฒด๋ฅผ ํ˜ธ์ถœํ•˜๋ฉด ํ”„๋ก์‹œ ๊ฐ์ฒด๋Š” ์‹ค์ œ ๊ฐ์ฒด์˜ ๋ฉ”์†Œ๋“œ ํ˜ธ์ถœ

 

em.find() : ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค๋ฅผ ํ†ตํ•ด์„œ ์‹ค์ œ ์—”ํ‹ฐํ‹ฐ ๊ฐ์ฒด ์กฐํšŒ

em.getReference() : ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์กฐํšŒ๋ฅผ ๋ฏธ๋ฃจ๋Š” ๊ฐ€์งœ(ํ”„๋ก์‹œ) ์—”ํ‹ฐํ‹ฐ ๊ฐ์ฒด ์กฐํšŒ

      // ํ˜ธ์ถœํ•œ ์ˆœ๊ฐ„ ์ฟผ๋ฆฌ ์‹คํ–‰
      Member findMember = em.find(Member.class, member.getId());
      // ํ˜ธ์ถœํ–ˆ์„ ๋•Œ ์‹คํ–‰ ์•ˆํ•จ 
      Member findMember2 = em.getReference(Member.class, member.getId());
      // ์ด๋•Œ ์ฟผ๋ฆฌ ์‹คํ–‰ ํ•จ -> ์‹ค์ œ ํ•„์š”ํ•œ ์‹œ์ ์— ์ฟผ๋ฆฌ ์‹คํ–‰
      System.out.println("findMember = " + findMember.getName());

 

 

ํ”„๋ก์‹œ ๊ฐ์ฒด์˜ ์ดˆ๊ธฐํ™”

Client์—์„œ Member์˜ ์ด๋ฆ„์„ ์š”์ฒญํ–ˆ์„ ๋•Œ ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ์— ์ œ์ผ ๋จผ์ € ์ดˆ๊ธฐํ™”๋ฅผ ์š”์ฒญํ•œ ํ›„ ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ๊ฐ€ ์‹ค์ œ Entity๋ฅผ ๋งŒ๋“ ๊ฒƒ์„ ์‚ฌ์šฉํ•ด์„œ ์ดˆ๊ธฐํ™”๋ฅผ ํ•œ๋‹ค. ๊ทธ ์ดํ›„๋กœ ์ด๋ฆ„์„ ์š”์ฒญํ–ˆ์„ ๋•Œ taget์œผ๋กœ ๋˜์–ด์žˆ๋Š” Member๋ฅผ ์กฐํšŒํ•˜๊ธฐ ๋•Œ๋ฌธ์— ๋‹ค์‹œ DB์กฐํšŒ๋ฅผ ํ•˜์ง€ ์•Š์•„๋„ ๋œ๋‹ค.

ํ”„๋ก์‹œ์˜ ํŠน์ง•

- ํ”„๋ก์‹œ ๊ฐ์ฒด๋Š” ์ฒ˜์Œ ์‚ฌ์šฉํ•  ๋•Œ ํ•œ ๋ฒˆ๋งŒ ์ดˆ๊ธฐํ™”

- ํ”„๋ก์‹œ ๊ฐ์ฒด๋ฅผ ์ดˆ๊ธฐํ™” ํ•  ๋•Œ, ํ”„๋ก์‹œ ๊ฐ์ฒด๊ฐ€ ์‹ค์ œ ์—”ํ‹ฐํ‹ฐ๋กœ ๋ฐ”๋€Œ๋Š” ๊ฒƒ์€ ์•„๋‹˜ -> ์ดˆ๊ธฐํ™”๋˜๋ฉด ํ”„๋ก์‹œ ๊ฐ์ฒด๋ฅผ ํ†ตํ•ด์„œ ์‹ค์ œ ์—”ํ‹ฐํ‹ฐ์— ์ ‘๊ทผ ๊ฐ€๋Šฅ

- ํ”„๋ก์‹œ ๊ฐ์ฒด๋Š” ์›๋ณธ ์—”ํ‹ฐํ‹ฐ๋ฅผ ์ƒ์†๋ฐ›์Œ, ๋”ฐ๋ผ์„œ ํƒ€์ž… ์ฒดํฌ์‹œ ์ฃผ์˜ํ•ด์•ผํ•จ ( == ๋น„๊ต ๋Œ€์‹  instance of ์‚ฌ์šฉ )

      Member m1 = em.find(Member.class, member1.getId());
      Member m2 = em.find(Member.class, member2.getId());


      Member reference1 = em.getReference(Member.class, member1.getId());
      Member reference2 = em.getReference(Member.class, member2.getId());
           
      // true
      System.out.println("m1 == m2 : "+(m1.getClass() == m2.getClass()));
      // false
      System.out.println("reference1 == reference2 : " +(m1.getClass() == reference2.getClass()));
      // true      
      System.out.println("reference1 == reference2 : " +(m1 instanceof Member));
      // true
      System.out.println("reference1 == reference2 : " +(m2 instanceof Member));

ํŒŒ๋ผ๋ฏธํ„ฐ๋กœ ํ”„๋ก์‹œ๋กœ ๋“ค์–ด์˜ฌ์ง€ ์‹ค์ œ๋กœ ๋“ค์–ด์˜ฌ์ง€ ๋ชจ๋ฅด๊ธฐ ๋•Œ๋ฌธ์— == ๋น„๊ต๋Š” ์ ˆ๋•Œ ์‚ฌ์šฉํ•˜์ง€ ๋ง๊ฒƒ

ํƒ€์ž…์„ ๋น„๊ตํ•  ๋•Œ๋Š” ๊ผญ instanceof ๋ฅผ ์‚ฌ์šฉํ•ด๋ผ!

 

- ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ์— ์ฐพ๋Š” ์—”ํ‹ฐํ‹ฐ๊ฐ€ ์ด๋ฏธ ์žˆ์œผ๋ฉด em.getreference()๋ฅผ ํ˜ธ์ถœํ•ด๋„ ์‹ค์ œ ์—”ํ‹ฐํ‹ฐ๊ฐ€ ๋ฐ˜ํ™˜ํ•œ๋‹ค.

	// m1.getClass -> ์‹ค์ œ ํด๋ž˜์Šค ๋ฐ˜ํ™˜
	Member m1 = em.find(Member.class, member1.getId());
	// m1.getClass -> ์‹ค์ œ ํด๋ž˜์Šค ๋ฐ˜ํ™˜
	Member reference = em.getReference(Member.class,member1.getId());
    

* ํ•œ ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ์—์„œ ํ˜ธ์ถœํ–ˆ๊ณ , PK๊ฐ€ ๊ฐ™๋‹ค๊ณ  ํ•œ๋‹ค๋ฉด ์ด๋ฏธ ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ์— ์žˆ๋Š” ๊ฐ์ฒด๋ฅผ ํ”„๋ก์‹œ๋กœ ๋ฐ˜ํ™˜ํ•ด๋ดค์ž ์˜๋ฏธ๊ฐ€ ์—†๊ธฐ ๋•Œ๋ฌธ์— ์‹ค์ œ ํด๋ž˜์Šค๋ฅผ ๋ฐ˜ํ™˜ํ•œ๋‹ค.

* JPA๋Š” ํ•˜๋‚˜์˜ ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ์—์„œ ์กฐํšŒํ•˜๋Š” ๊ฐ™์€ ์—”ํ‹ฐํ‹ฐ์˜ ๋™์ผ์„ฑ์„ ๋ณด์žฅํ•œ๋‹ค.

 

๋ฐ˜๋Œ€๋กœ ์•„๋ž˜์™€ ๊ฐ™์ด proxy ๊ฐ์ฒด๋ฅผ ๋จผ์ € ํ˜ธ์ถœํ•˜๊ณ  ์‹ค์ œ ๊ฐ์ฒด๋ฅผ ํ˜ธ์ถœํ•˜๊ฒŒ ๋œ๋‹ค๋ฉด?

	// m1.getClass -> Proxy ๊ฐ์ฒด ๋ฐ˜ํ™˜
	Member reference = em.getReference(Member.class,member1.getId());
	// m1.getClass -> Proxy ๊ฐ์ฒด ๋ฐ˜ํ™˜
	Member m1 = em.find(Member.class, member1.getId());

 

- ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ์˜ ๋„์›€์„ ๋ฐ›์„ ์ˆ˜ ์—†๋Š” ์ค€์˜์† ์ƒํƒœ์ผ ๋•Œ, ํ”„๋ก์‹œ๋ฅผ ์ดˆ๊ธฐํ™”ํ•˜๋ฉด ๋ฌธ์ œ์ 

-> clear ํ›„์— getName์„ ์กฐํšŒํ•˜๋ฉด not initialize proxy ์—๋Ÿฌ๊ฐ€ ๋œฌ๋‹ค.( ๋”์ด์ƒ ์ปจํ…์ŠคํŠธ์˜ ๋„์›€์„ ๋ฐ›์ง€ ๋ชปํ•จ)

      Member reference1 = em.getReference(Member.class, member1.getId());
      System.out.println(reference1.getClass());
      em.clear();
      System.out.println(reference1.getName());

 

 

ํ”„๋ก์‹œ ํ™•์ธ

- ํ”„๋ก์‹œ ์ธ์Šคํ„ด์Šค์˜ ์ดˆ๊ธฐํ™” ์—ฌ๋ถ€ ํ™•์ธ

	EntityManagerFactory emf = Persistence.createEntityManagerFactory("hello");
	PersistenceUnitUtil persistenceUnitUtil = emf.getPersistenceUnitUtil();


	Member reference1 = em.getReference(Member.class, member1.getId());
	System.out.println(reference1.getName());
	// true
	System.out.println(persistenceUnitUtil.isLoaded(reference1));

- ํ”„๋ก์‹œ ํด๋ž˜์Šค ํ™•์ธ ๋ฐฉ๋ฒ•

entitiy.getClas().getName() ์ถœ๋ ฅ

- ํ”„๋ก์‹œ ๊ฐ•์ œ ์ดˆ๊ธฐํ™”

ํ•ด๋‹น entity๋ฅผ ๊ฐ•์ œ ์ดˆ๊ธฐํ™” ํ•œ๋‹ค.

Hibernate.initalize(member);

 

์ฆ‰์‹œ ๋กœ๋”ฉ๊ณผ ์ง€์—ฐ ๋กœ๋”ฉ

* Member์™€ Team์—์„œ Team์€ ์ž˜ ์‚ฌ์šฉํ•˜์ง€ ์•Š๋Š”๋‹ค ํ–ˆ์„ ๋•Œ

์ง€์—ฐ ๋กœ๋”ฉ LAZY์„ ์‚ฌ์šฉํ•ด์„œ ํ”„๋ก์‹œ๋กœ ์กฐํšŒ

Member ์™€ ManyToOne ๊ด€๊ณ„์— ์žˆ๋Š” Team์„ ์กฐํšŒํ•  ๋•Œ ํ”„๋ก์‹œ๋ฅผ ์‚ฌ์šฉํ•˜๊ฒ ๋‹ค. ๋ผ๊ณ  ์ •์˜ ํ•˜๋Š” ๊ฒƒ์ด๋‹ค.(Member๋งŒ DB์—์„œ ์กฐํšŒ)

  @ManyToOne(fetch = FetchType.LAZY)
  @JoinColumn(name = "TEAM_ID")
  private Team team;

- ์•„๋ž˜์˜ ๊ทธ๋ฆผ ์ฒ˜๋Ÿผ Member๋งŒ ์กฐํšŒ ํ–ˆ์„ ๋•Œ ์—ฐ๊ด€๊ด€๊ณ„์— ์žˆ๋Š” Team์€ ์กฐํšŒํ•˜์ง€ ์•Š๊ณ  Member ๋งŒ์„ ์กฐํšŒํ•œ๋‹ค. (Team๋Š” ๊ฐ€์งœ์ธ proxy๊ฐ์ฒด๊ฐ€ ์žˆ์–ด์„œ ์กฐํšŒ๋˜์ง€ ์•Š์Œ)

- ๋งŒ์•ฝ Member์—์„œ Team ๊ด€๋ จ ์กฐํšŒ๋ฅผ ํ–ˆ์„ ๋•Œ ๊ทธ ์‹œ์ ์—์„œ ์ดˆ๊ธฐํ™”๊ฐ€ ๋œ๋‹ค( DB์—์„œ ์ง์ ‘ ์กฐํšŒ )

 

* Member์™€ Team์—์„œ ์ž์ฃผ ํ•จ๊ป˜ ์‚ฌ์šฉํ•œ๋‹ค๋ฉด?

์ฆ‰์‹œ ๋กœ๋”ฉ EAGER๋ฅผ ์‚ฌ์šฉํ•ด์„œ ํ•จ๊ป˜ ์กฐํšŒ ( Proxy๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ์•Š๋Š”๋‹ค )

- ๊ฐ€๋Šฅํ•˜๋ฉด JPA๋Š” ์กฐ์ธ์œผ๋กœ ํ•œ๋ฒˆ์— ์กฐํšŒํ•œ๋‹ค.

  @ManyToOne(fetch = FetchType.EAGER)
  @JoinColumn(name = "TEAM_ID")
  private Team team;

 

* ์ฃผ์˜ํ• ์ 

- ๊ฐ€๊ธ‰์  ์ง€์—ฐ ๋กœ๋”ฉ๋งŒ ์‚ฌ์šฉ ํ•œ๋‹ค. -> Member์™€ Team์„ ๊ฐ™์ด ์กฐํšŒํ•˜๊ณ  ์‹ถ๋‹ค๋ฉด JPQL fetch join์ด๋‚˜ ์—”ํ‹ฐํ‹ฐ ๊ทธ๋ž˜ํ”„ ๊ธฐ๋Šฅ์œผ๋กœ ํ•ด๊ฒฐํ•œ๋‹ค.

- ์ฆ‰์‹œ ๋กœ๋”ฉ์„ ์ ์šฉํ•˜๋ฉด ์˜ˆ์ƒํ•˜์ง€ ๋ชปํ•œ SQL ๋ฐœ์ƒ

- ์ฆ‰์‹œ ๋กœ๋”ฉ์€ JPQL์—์„œ N+1 ๋ฌธ์ œ๋ฅผ ์ผ์œผํ‚จ๋‹ค.

- @ManyToOne, @OneToOne ์€ ๊ธฐ๋ณธ์ด ์ฆ‰์‹œ ๋กœ๋”ฉ --> LAZY๋กœ ์„ค์ •

- @OneToMany, @ManyToMany ๋Š” ๊ธฐ๋ณธ์ด ์ง€์—ฐ ๋กœ๋”ฉ 

 

 

์˜์†์„ฑ ์ „์ด : CASCADE

ํŠน์ • ์—”ํ‹ฐํ‹ฐ๋ฅผ ์˜์† ์ƒํƒœ๋กœ ๋งŒ๋“ค ๋•Œ ์—ฐ๊ด€๋œ ์—”ํ‹ฐํ‹ฐ๋„ ํ•จ๊ป˜ ์˜์† ์ƒํƒœ๋กœ ๋งŒ๋“ค๊ณ  ์‹ถ์„ ๋•Œ

-> ๋ถ€๋ชจ ์—”ํ‹ฐํ‹ฐ๋ฅผ ์ €์žฅํ•  ๋•Œ ์ž์‹ ์—”ํ‹ฐํ‹ฐ๋„ ํ•จ๊ป˜ ์ €์žฅํ•œ๋‹ค.

์•„๋ž˜์™€ ๊ฐ™์ด ์—ฐ๊ด€๊ด€๊ณ„ ํŽธ์˜ ๋ฉ”์„œ๋“œ๋ฅผ ๋งŒ๋“ ๋‹ค.

	@Entity
	public class Parent{

	@OneToMany(mappedBy="parent",cascade = CascadeType.ALL)
	private List<Child> childList = new ArrayList<>();
    
	public void addChild(Child child){
		childList.add(child);
		child.setParent(this);
	}

์—ฌ๊ธฐ์„œ cascade๋ฅผ ๊ฑธ์–ด์ฃผ๋ฉด Parent๋ฅผ persistํ•  ๋•Œ Child๋„ ๊ฐ™์ด persist ํ•ด์ค€๋‹ค. 

์ฃผ์˜ ) ์˜์†์„ฑ ์ „์ด๋Š” ์—ฐ๊ด€๊ด€๊ณ„๋ฅผ ๋งคํ•‘ํ•˜๋Š” ๊ฒƒ๊ณผ ์•„๋ฌด ๊ด€๋ จ์ด ์—†์Œ!!!

๊ทธ์ € ์—”ํ‹ฐํ‹ฐ๋ฅผ ์˜์†ํ™”ํ•  ๋•Œ ์—ฐ๊ด€๋œ ์—”ํ‹ฐํ‹ฐ๋„ ํ•จ๊ป˜ ์˜์†ํ™” ์‹œํ‚ค๋Š” ํŽธ๋ฆฌํ•จ์„ ์ œ๊ณตํ•  ๋ฟ์ด๋‹ค.

 

CASCADE์˜ ์ข…๋ฅ˜

- ALL - ๋ชจ๋‘ ์ ์šฉ * ํ•ด๋‹น ์—”ํ‹ฐํ‹ฐ์™€ ๋ผ์ดํ”„์‚ฌ์ดํด์ด ๊ฐ™์„ ๋•Œ ์‚ฌ์šฉํ•œ๋‹ค -> ํ•ด๋‹น ๊ฐ์ฒด๊ฐ€ ๋‹ค๋ฅธ๊ณณ์—์„œ๋„ ์‚ฌ์šฉ๋  ๋•Œ ์‚ฌ์šฉ X

- PERSIST - ์˜์† * ์ €์žฅํ•  ๋•Œ๋งŒ ์“ธ๊ฒŒ (์‚ญ์ œ์— ๋Œ€ํ•ด ์กฐ์‹ฌํ•  ๋•Œ)

- REMOVE - ์‚ญ์ œ

 ๋“ฑ ๋‹ค๋ฅธ ์ข…๋ฅ˜๋„ ์žˆ์ง€๋งŒ ๋ณดํ†ต ALL or PERSIST๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค.

 

๊ณ ์•„ ๊ฐ์ฒด

๊ณ ์•„ ๊ฐ์ฒด ์ œ๊ฑฐ : ๋ถ€๋ชจ ์—”ํ‹ฐํ‹ฐ์™€ ์—ฐ๊ด€๊ด€๊ณ„๊ฐ€ ๋Š์–ด์ง„ ์ž์‹ ์—”ํ‹ฐํ‹ฐ๋ฅผ ์ž๋™์œผ๋กœ ์‚ญ์ œ

Cascade ์™€ orphanRemoval๋ฅผ๊ฑธ์–ด์ค€๋‹ค.

	@OneToMany(mappedBy="parent",cascade = CascadeType.ALL, orphanRemoval=true)

 

๋กœ์ง์—์„œ Parent ์˜ Child List ์—์„œ ์„ ํƒํ•œ Child ์š”์†Œ๋ฅผ remove ํ•˜๋ฉด DB์—์„œ๋„ ์‚ญ์ œ๊ฐ€ ๋œ๋‹ค.

( ์ปฌ๋ ‰์…˜์—์„œ remove ํ•˜๋Š”๋ฐ๋„ DB์—์„œ ๊ฐ™์ด ์‚ฌ๋ผ์ง) 

 

* ์ฃผ์˜ *

- ์ฐธ์กฐํ•˜๋Š” ๊ณณ์ด ํ•˜๋‚˜์ผ ๋•Œ ์‚ฌ์šฉํ•ด์•ผํ•จ!

- ํŠน์ • ์—”ํ‹ฐํ‹ฐ๊ฐ€ ๊ฐœ์ธ ์†Œ์œ ํ•  ๋•Œ ์‚ฌ์šฉ

- @OneToOne, @OneToMany๋งŒ ๊ฐ€๋Šฅํ•˜๋‹ค.

- CascadeType.Remove์ฒ˜๋Ÿผ ์ž‘๋™ํ•œ๋‹ค.

 

์˜์†์„ฑ ์ „์ด + ๊ณ ์•„ ๊ฐ์ฒด, ์ƒ๋ช…์ฃผ๊ธฐ

๋‘˜๋‹ค ์‚ฌ์šฉํ•˜๊ฒŒ ๋˜๋ฉด ๋ถ€๋ชจ ์—”ํ‹ฐํ‹ฐ๋ฅผ ํ†ตํ•ด์„œ ์ž์‹์˜ ์ƒ๋ช…์ฃผ๊ธฐ๋ฅผ ๊ด€๋ฆฌํ•  ์ˆ˜ ์žˆ๋‹ค.

์˜ˆ๋ฅผ ๋“ค์–ด์„œ ๋ถ€๋ชจ ์—”ํ‹ฐํ‹ฐ๊ฐ€ Repository๋ฅผ ์ด์šฉํ•˜์—ฌ ์‚ญ์ œ๋ฅผ ํ–ˆ์„ ๋•Œ ์ž์‹์€ Repository๋ฅผ ๋งŒ๋“ค ํ•„์š” ์—†์ด ์ง€์›Œ์ง€๊ฒŒ ๋œ๋‹ค.

 

๋ฐ˜์‘ํ˜•