JiwonDev

JPA #6 ๋‹ค์–‘ํ•œ ์—ฐ๊ด€๊ด€๊ณ„ ๋งคํ•‘ (1:N, N:1, N:N)

by JiwonDev

๐Ÿ“Œ ์—ฐ๊ด€๊ด€๊ณ„ ์• ๋…ธํ…Œ์ด์…˜

์ฐธ๊ณ ๋กœ ์ด๋Ÿฐ 1:1, N:1 ์กฐ๊ฑด์„ ํ–‰์˜ ๊ฐœ์ˆ˜ ๋น„์œจ ์ œ์•ฝ ์กฐ๊ฑด ( Cardinality Raito Constraint ) ์ด๋ผ๊ณ  ํ•œ๋‹ค.

JPA์—์„œ ์‚ฌ์šฉ๋ฒ•์€ ์ •๋ง ๊ฐ„๋‹จํ•˜๊ธด ํ•˜๋‹ค.

• ๋‹ค๋Œ€์ผ: @ManyToOne 
• ์ผ๋Œ€๋‹ค: @OneToMany 
• ์ผ๋Œ€์ผ: @OneToOne 
• ๋‹ค๋Œ€๋‹ค: @ManyToMany

 

์ฐธ๊ณ ๋กœ ๊ฐ ์• ๋…ธํ…Œ์ด์…˜์˜ ์˜ต์…˜์€ ์•„๋ž˜์™€ ๊ฐ™๋‹ค.

fetch์™€ cascade๋Š” ๋‹ค์Œ ๊ธ€์—์„œ ์„ค๋ช…ํ•  ์˜ˆ์ •์ด๋‹ˆ, ๊ฐ„๋‹จํ•˜๊ฒŒ ๋ณด๊ณ  ๋„˜์–ด๊ฐ€์ž

 

@ManyToOne

mappedBy๊ฐ€ ์—†๋‹ค. ํ•ญ์ƒ Many์ชฝ์ด ์—ฐ๊ด€๊ด€๊ณ„์˜ ์ฃผ์ธ์ด ๋˜์–ด์•ผํ•œ๋‹ค.

 

@OneToMany

 

@JoinColumn (์™ธ๋ž˜ํ‚ค ๋งคํ•‘ ์šฉ๋„)

 

@JoinTable ( N:N ๊ด€๊ณ„ ์‚ฌ์šฉ์‹œ ์กฐ์ธํ…Œ์ด๋ธ” ์ง€์ • )

@JoinTable(name="JOIN_TABLE") ์ด๋ ‡๊ฒŒ ์‚ฌ์šฉํ•จ. ๊ทธ ์™ธ๋Š” ๋‹ค๋Œ€๋‹ค ๊ด€๊ณ„๋ฅผ ์‚ฌ์šฉํ•  ์ผ์ด ์—†์œผ๋ฏ€๋กœ ์ƒ๋žต.

 

๋ณต์Šต

๐Ÿ’ญ mappedBy๋ฅผ ์•ˆํ•˜๋ฉด? ๋งคํ•‘ ํ…Œ์ด๋ธ”์ด ์ƒ๊ธด๋‹ค.
: DB๋Š” ์™ธ๋ž˜ํ‚ค ํ•˜๋‚˜๋กœ ์–‘๋ฐฉํ–ฅ ์ฐธ์กฐ๊ฐ€ ๊ฐ€๋Šฅํ•˜๋‹ค.
: JPA(๊ฐ์ฒด)๋Š” ์ฐธ์กฐ์— ๋ฐฉํ–ฅ์ด ์žˆ๋‹ค. ๋‹จ๋ฐฉํ–ฅ์ด๋‹ค.

: DB ์—๋Š” ์ปฌ๋ ‰์…˜์ด๋ผ๋Š” ๊ฐœ๋…์ด ์—†๋‹ค. ์™ธ๋ž˜ํ‚ค๋งŒ ์žˆ์„ ๋ฟ์ด๋‹ค.
: JPA ์ž…์žฅ์—์„œ๋Š” ์–ด์ฉ” ์ˆ˜ ์—†์ด, ๋งคํ•‘ ํ…Œ์ด๋ธ”๋กœ ์ปฌ๋ ‰์…˜์„ ๊ตฌํ˜„ํ•œ๋‹ค.
: ์™ธ๋ž˜ํ‚ค๋กœ ๊ตฌํ˜„ํ•˜๊ณ  ์‹ถ๋‹ค๋ฉด? -> mappedBy

 

# DB ์นผ๋Ÿผ๋ช…์„ ์ ์œผ์…”์•ผ ํ•ด์š”.

์ฐธ๊ณ ๋กœ '์™ธ๋ž˜ํ‚ค๊ฐ€ ์ฐธ์กฐํ•˜๋Š” ํ…Œ์ด๋ธ”์˜ ์นผ๋Ÿผ๋ช…'์€ DB ์นผ๋Ÿผ๋ช…์„ ์˜๋ฏธํ•œ๋‹ค. ์ž๋ฐ” ์ฝ”๋“œ๋ฅผ ์˜๋ฏธํ•˜๋Š”๊ฒŒ ์•„๋‹ˆ๋‹ค.

ํ•˜์ง€๋งŒ ๊ทธ๋ƒฅ ์นด๋ฉœ์ผ€์ด์Šค๋กœ ์“ฐ๋Š” ๊ฒฝ์šฐ๊ฐ€ ๋งŽ์•„ ์ž๋ฐ” ์ฝ”๋“œ ์นผ๋Ÿผ๋ช…์ธ์ค„ ์ฐฉ๊ฐํ•˜๋Š” ๊ฒฝ์šฐ๊ฐ€ ์žˆ๋‹ค. ์ด๋Š” SpringPhysicalNamingStrategy ๊ฐ€ ๊ธฐ๋ณธ์œผ๋กœ ์ ์šฉ๋˜์–ด์žˆ์–ด @JoinColumn์— ์‚ฌ์šฉ๋˜๋Š” DB ์นผ๋Ÿผ๋ช… ์นด๋ฉœ์ผ€์ด์Šค (team_my_id -> teamMyId) ๋กœ ์ž…๋ ฅํ•ด๋„ ๋ณ€ํ™˜ํ•ด์ฃผ๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.

  • JoinColumn(name="๋‚ด DB ํ…Œ์ด๋ธ” ์™ธ๋ž˜ํ‚ค ๋ช…", referencedColumnName="์ฐธ์กฐํ•  DB ํ…Œ์ด๋ธ” PK ๋ช…") ์ด ๊ธฐ๋ณธ ์‚ฌ์šฉ๋ฒ•์ด๋‹ค
  • name์„ ์ƒ๋žตํ•˜๋ฉด {ํ•„๋“œ๋ช… _ ์ฐธ์กฐ ํ…Œ์ด๋ธ” PK๋ช… }์œผ๋กœ ๋งคํ•‘๋œ๋‹ค. *์ฃผ์˜* ๋ณตํ•ฉ ์™ธ๋ž˜ํ‚ค์ธ๊ฒฝ์šฐ, ์กฐ์ธ๋ฌธ์ด๋‚˜ ํ‚ค์ˆœ์„œ๊ฐ€ ๋ฐ”๋€Œ๋Š” ๋ฒ„๊ทธ ์žˆ์Œ
  • referencedColumnName ์„ ์ƒ๋žตํ•˜๋ฉด { ์ฐธ์กฐ ํ…Œ์ด๋ธ” PK๋ช…  }๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค.
  • name๊ณผ referencedColumnName์€ DB ์นผ๋Ÿผ๋ช…์„ ๊ทธ๋Œ€๋กœ ์ ์–ด์•ผํ•˜์ง€๋งŒ, ์นด๋ฉœ์ผ€์ด์Šค๋กœ ์ ์–ด๋„ ๋งคํ•‘ํ•ด์ค€๋‹ค. ( myId -> my_id )
    ๊ทธ๋ ‡๊ฒŒ ์‚ฌ์šฉํ•  ์ผ์€ ์—†๊ฒ ์ง€๋งŒ, PhysicalNamingStrategy ๊ตฌํ˜„์ฒด๋ฅผ ๊นŒ๋ณด๋ฉด my_familyMotherId_type ์ด๋ ‡๊ฒŒ ์„ž์–ด๋„ ์ž˜ ๋งคํ•‘ํ•œ๋‹ค.

๐Ÿ“Œ @OneToMany

์•ž์„ ์‹œ๊ฐ„์— Member๊ธฐ์ค€์œผ๋กœ ๋‹จ๋ฐฉํ–ฅ (@ManyToOne)์œผ๋กœ ์—ฐ๊ด€๊ด€๊ณ„ ์ฃผ์ธ์„ ์„ค์ •ํ–ˆ์—ˆ๋‹ค.

@Entity
public class Member {
 
    @Id
    @GeneratedValue
    private Long id;
    
    @ManyToOne
    @JoinColumn(name = "TEAM_ID")
    private Team team;
	
}

DB์—์„œ๋Š” ์ด๊ฒŒ ์ž์—ฐ์Šค๋Ÿฌ์šด ๋ฐฉ๋ฒ•.

 

 

๊ทธ๋Ÿฐ๋ฐ ์ด๋Š” ๋น„์ฆˆ๋‹ˆ์Šค๋งˆ๋‹ค ๋‹ค๋ฅด๋‹ค. Team์œผ๋กœ Member๋ฅผ ์กฐํšŒํ•˜๋Š” ์„œ๋น„์Šค์ผ ์ˆ˜๋„ ์žˆ๋‹ค.

์‰ฝ๊ฒŒ๋งํ•ด์„œ Team์€ Member ์ •๋ณด๋ฅผ ์•Œ์•„์•ผํ•˜์ง€๋งŒ, ๋ฐ˜๋Œ€๋กœ Member๋Š” Team์˜ ์ •๋ณด๊ฐ€ ํ•„์š”์—†๋Š” ๊ฒฝ์šฐ.

์ด ๊ฒฝ์šฐ ์—ฐ๊ด€๊ด€๊ณ„ ์ฃผ์ธ์€ Team์ด ๋˜๊ณ , ์ผ๋Œ€๋‹ค (@OneToMany) ๊ด€๊ณ„๊ฐ€ ๋œ๋‹ค.

@Entity
public class Team {

    @Id
    @GeneratedValue
    @Column(name = "TEAM_ID")
    private Long id;

    @OneToMany
    @JoinColumn(name = "TEAM_ID") // ์ด๊ฒŒ ์—†์œผ๋ฉด ํ…Œ์ด๋ธ”์„ ์ถ”๊ฐ€๋กœ ๋งŒ๋“ค์–ด์„œ ์‚ฌ์šฉํ•˜๊ฒŒ๋œ๋‹ค.
    List<Member> members = new ArrayList<Member>();

    private String name;
…
}

 

* ์ฐธ๊ณ ๋กœ @JoinColumn์„ ์‚ฌ์šฉํ•˜์ง€ ์•Š์œผ๋ฉด, ๊ธฐ๋ณธ ์ฒ˜๋ฆฌ๋ฐฉ์‹์ด ์กฐ์ธํ•˜๋Š”๊ฒŒ ์•„๋‹ˆ๋ผ์„œ ์ค‘๊ฐ„์— ํ…Œ์ด๋ธ”์„ ์ถ”๊ฐ€ํ•ด์„œ ์ฒ˜๋ฆฌํ•œ๋‹ค.

์กฐ์ธํ•˜์ง€ ์•Š๊ณ  DB์— team_member๋ผ๋Š” ํ…Œ์ด๋ธ”์„ ๋ฉ‹๋Œ€๋กœ ์ถ”๊ฐ€ํ•ด๋ฒ„๋ฆฐ๋‹ค.

๋น„์ฆˆ๋‹ˆ์Šค๋‚˜ ๊ฐ์ฒด๋Š” ์ด๋Ÿฐ ์ผ์ด ๊ฐ€๋Šฅํ•˜๋‹ค. ํ•˜์ง€๋งŒ DB๋Š” ์„ค๊ณ„์ƒ ๋ถˆ๊ฐ€๋Šฅํ•˜๋‹ค. Member(Many)์ชฝ์— ์™ธ๋ž˜ํ‚ค๊ฐ€ ์žˆ์„ ์ˆ˜ ๋ฐ–์— ์—†๋‹ค. ์ฆ‰ Team ๊ด€๊ณ„(์™ธ๋ž˜ํ‚ค)๋ฅผ ๋ณ€๊ฒฝํ•˜๋ฉด ์ˆ˜๋งŽ์€ Member์— UPDATE ์ฟผ๋ฆฌ๊ฐ€ ๋‚˜๊ฐ€๊ฒŒ ๋œ๋‹ค.

team.getMembers.add(member); ๋ฅผ ํ•ด๋ณด๋ฉด ๋ฉค๋ฒ„ ํ…Œ์ด๋ธ”์— ์—…๋ฐ์ดํŠธ ์ฟผ๋ฆฌ๊ฐ€ ๋‚˜๊ฐ„๋‹ค.

 

๋‹ค๋Œ€์ผ ์ฟผ๋ฆฌ์™€ ๋‹ค๋ฅด๊ฒŒ ์ž์‹ ์ด ์•„๋‹Œ ๋‹ค๋ฅธ ํ…Œ์ด๋ธ”๊นŒ์ง€ ์ˆ˜๋งŽ์€ ์ฟผ๋ฆฌ๋ฅผ ๋‚ ๋ ค์•ผํ•œ๋‹ค๋Š” ๋‹จ์ ์ด ์žˆ๋‹ค.

์ด๋Š” Team์„ ์ˆ˜์ •ํ–ˆ๋Š”๋ฐ Member๊นŒ์ง€ ๋ณ€๊ฒฝ์ด ์ „ํŒŒ๋˜๋Š” ๊ฒƒ์ด๋‹ค. ์‹ค๋ฌด์—์„œ๋Š” ์ˆ˜๋งŽ์€ ํ…Œ์ด๋ธ”์„ ์‚ฌ์šฉํ•  ๊ฑด๋ฐ ๋งค๋ฒˆ 1:N์ธ์ง€ N:1์ธ์ง€ ํ™•์ธํ•ด๊ฐ€๋ฉด์„œ ์กฐํšŒํ•˜๋Š”๊ฑด ๊ฐ์ฒด์ง€ํ–ฅ์ ์ด์ง€๋„ ์•Š๊ณ , ์‚ฌ์‹ค์ƒ ๋ถˆ๊ฐ€๋Šฅํ•˜๋‹ค.

 

๊ทธ๋ž˜์„œ ์‹ค๋ฌด์—์„œ๋Š” Team โžก Member ์กฐํšŒ๊ฐ€ ํ•„์š”ํ•œ ๊ฒฝ์šฐ, ์ฐจ๋ผ๋ฆฌ ๋‹ค๋Œ€์ผ ์–‘๋ฐฉํ–ฅ(@ManyToOne)์„ ์“ฐ๋Š”๊ฑธ ๊ถŒ์žฅํ•œ๋‹ค. [ ์–‘๋ฐฉํ–ฅ vs ์ผ๋Œ€๋‹ค ] ์˜ ์„ ํƒ์€ ์กฐ๊ธˆ ์• ๋งคํ•œ ๋ถ€๋ถ„์ด์ง€๋งŒ, ํŠธ๋ ˆ์ด๋“œ ์˜คํ”„๋ฅผ ๊ณ ๋ คํ•ด๋ณด๋ฉด ๊ฑฐ์˜ ๋Œ€๋ถ€๋ถ„์€ ์ด๊ฒŒ ๋งž๋‹ค.

 

 

โœ” @OneToMany๋ฅผ ์–‘๋ฐฉํ–ฅ์ฒ˜๋Ÿผ ์“ฐ๋Š” ๋ฐฉ๋ฒ•

๐Ÿ™„ : ?? ๋ฌด์ง€์„ฑ์œผ๋กœ ์–‘์ชฝ์— @JoinColumn ๋ถ™์ด๋ฉด ์•ˆ๋˜๋‚˜์š”?

๋”๋ณด๊ธฐ

์‚ฌ์šฉ ์‹œ JPA์—์„œ ์˜ค๋ฅ˜๋ฅผ ๋„์šฐ๋ฉฐ, ๋œ๋‹ค๊ณ  ํ•˜๋”๋ผ๋„ ์ ˆ๋Œ€ ์‚ฌ์šฉํ•ด์„œ๋Š” ์•ˆ๋˜๋Š” ์ฝ”๋“œ์ด๋‹ค.

JPA์—์„œ๋Š” ์–‘๋ฐฉํ–ฅ ๊ด€๊ณ„์—์„œ [์—ฐ๊ด€๊ด€๊ณ„์˜ ์ฃผ์ธ]์„ ํ•œ์ชฝ์œผ๋กœ ์ง€์ •ํ•œ๋‹ค.
๊ทธ ์ด์œ ๋Š” ์–‘์ชฝ์„ ์ฃผ์ธ์œผ๋กœ ์ง€์ •ํ•˜๋Š”๊ฒŒ ๋ถˆ๊ฐ€๋Šฅํ•ด์„œ ๊ทธ๋Ÿฐ๊ฒŒ ์•„๋‹ˆ๋ผ, ์˜ˆ์ธกํ•  ์ˆ˜ ์—†๋Š” ๋™์ž‘์„ ์ดˆ๋ž˜ํ•˜๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.


* ์‹ค์ œ๋กœ ์Šคํ”„๋ง์—์„œ ์‚ฌ์šฉํ•˜๋ฉด, ์ปดํŒŒ์ผ์€ ๋˜์ง€๋งŒ ์‹คํ–‰์‹œ ์•„๋ž˜์™€ ๊ฐ™์ด ์˜ค๋ฅ˜๋œจ๋ฉฐ ์•ฑ์ด ๊บผ์ง„๋‹ค.

2022-01-30 17:32:12.955 ERROR 24436 
---[  restartedMain] j.LocalContainerEntityManagerFactoryBean :
  Failed to initialize JPA EntityManagerFactory:
    Associations marked as mappedBy must not define database mappings like @JoinTable or @JoinColumn: Team.members


์ฆ‰, ์–‘์ชฝ์— @JoinColumn์„ ์“ฐ๋ฉด ์–‘์ชฝ ๋‹ค [์—ฐ๊ด€๊ด€๊ณ„์˜ ์ฃผ์ธ]์ด ๋˜์–ด๋ฒ„๋ฆฌ๊ณ , ์ด๋Š” ์˜ˆ์ธกํ•  ์ˆ˜ ์—†๋Š” ๋™์ž‘ => ์˜ค๋ฅ˜๋ฅผ ๋งŒ๋“ค์–ด๋‚ธ๋‹ค. ๊ทธ๋ž˜์„œ ์‚ฌ์šฉํ•˜์ง€ ๋ชปํ•˜๊ฒŒ ๋ง‰๋Š” ๊ฒƒ์ด๋‹ค.

๋ฐ˜๋ฉด mappedBy๋Š” ํ•œ์ชฝ์„ ์ฝ๊ธฐ์ „์šฉ(๊ฐ€์งœ๋งคํ•‘)์œผ๋กœ ๋งŒ๋“ค์–ด๋ฒ„๋ ค์„œ ์™ธ๋ž˜ํ‚ค ํ•˜๋‚˜๋กœ ์–‘์ชฝ ์ฐธ์กฐ๊ฐ€ ๊ฐ€๋Šฅํ•˜๊ฒŒ ํ•ด์ค€๋‹ค.
๋ฌผ๋ก  ์ฃผ์ธ์ด ์•„๋‹Œ์ชฝ์€ ์™ธ๋ž˜ํ‚ค ์ˆ˜์ •์ด ๋ถˆ๊ฐ€๋Šฅํ•˜์ง€๋งŒ.

https://stackoverflow.com/questions/14012494/hibernate-joincolumn-in-both-entities-for-1-m-relationship

 

Hibernate @JoinColumn in both entities for 1-m relationship

Suppose there is a 1-m relationship between Department and Employee which department can have many employees and one employee can be in only one department. I have depId as a foreign key in the Emp...

stackoverflow.com

 

 

JPA์—์„œ ๊ณต์‹์ ์œผ๋กœ ์ œ๊ณตํ•ด์ฃผ๋Š” ๊ธฐ๋Šฅ์€ ์—†๋‹ค. ์™œ๋ƒํ•˜๋ฉด @ManyToOne ์—๋Š” mappedBy๋ผ๋Š” ์˜ต์…˜์ด ์—†๊ธฐ ๋•Œ๋ฌธ.

 

๋‹ค๋งŒ ๊ผผ์ˆ˜๋กœ ๋น„์Šทํ•˜๊ฒŒ ๋งŒ๋“ค ์ˆ˜๋Š” ์žˆ๋Š”๋ฐ  ์ผ๋Œ€๋‹ค(@OneToMany)๋ฅผ ์‚ฌ์šฉํ•˜๋Š”๋ฐ ์–‘๋ฐฉํ–ฅ์œผ๋กœ ์กฐํšŒํ•˜๊ณ  ์‹ถ๋‹ค๋ฉด ์•„๋ž˜์™€ ๊ฐ™์ด ํ•˜๋ฉด๋œ๋‹ค.

์ •ํ™•ํžˆ๋Š” ์–‘๋ฐฉํ–ฅ ๋งคํ•‘์€ ์•„๋‹ˆ๊ณ , ์–‘์ชฝ์„ ์ฃผ์ธ์œผ๋กœ ์„ค์ • ํ›„, ํ•œ์ชฝ์„ ์ฝ๊ธฐ์ „์šฉ์œผ๋กœ ๋งŒ๋“ฆ.

@Entity
public class Member{
	
    @ManyToOne // JoinColumn์„ ์ฃผ์ธ์ด ์•„๋‹Œ์ชฝ์—๋„ ์ง€์ •ํ•˜๋˜, ์ˆ˜์ •์„ ๋ง‰์•„ DB ์ฝ๊ธฐ์ „์šฉ์œผ๋กœ ๋งŒ๋“ค์–ด๋ฒ„๋ฆฐ๋‹ค.
    @JoinColumn(insertable = false, updateable= false)
    private Team team;
}
@Entity
public class Team {

    @Id
    @GeneratedValue
    @Column(name = "TEAM_ID")
    private Long id;

    @OneToMany // Team์ด ์ฃผ์ธ์ด๊ธฐ ๋•Œ๋ฌธ์— members์— (mappedBy = "team")์„ ๊ฑธ์ง€ ์•Š๋Š”๋‹ค.
    @JoinColumn(name = "TEAM_ID")
    List<Member> members = new ArrayList<Member>();

    private String name;
…
}

์ด๋Ÿฐ ๊ฑธ ์•Œ๋ ค์ฃผ๋Š” ์ด์œ ๋Š” ์‹ค๋ฌด์—์„œ ์„œ๋น„์Šค๊ฐ€ ๋ณต์žกํ•ด์ง€๋ฉด ์ด๋Ÿฐ ํ…Œํฌ๋‹‰์ด ๊ฐ€๋” ํ•„์š”ํ•  ๋•Œ๊ฐ€ ์žˆ๋‹ค.

 

 

๐Ÿ“Œ @OneTOOne

์• ๋…ธํ…Œ์ด์…˜๋งŒ ๋‹ค๋ฅผ ๋ฟ, @ManyToOne๊ณผ ์‚ฌ์šฉ๋ฒ•์€ ๊ฐ™๋‹ค.

@Entity
public class Member{
    @OneToOne
    @JoinColumn(name="LOCKER_ID");
    private Locker locker;
}
@Entity
public class Locker{
    @OneToOne(mappedBy = "locker") // member.locker
    private Member member;
}

์ฐธ๊ณ ๋กœ DB์—์„œ์˜ ์ผ๋Œ€์ผ ๊ด€๊ณ„๋Š”, ์™ธ๋ž˜ํ‚ค์— ์œ ๋‹ˆํฌ ์ œ์•ฝ์กฐ๊ฑด(FK, UNI)์ด ์ถ”๊ฐ€๊ฐ€ ๋œ ๊ฒƒ์ด๋‹ค.

 

๋ณ„๋กœ ์ค‘์š”ํ•˜์ง€๋Š” ์•Š์ง€๋งŒ, ๋‹จ๋ฐฉํ–ฅ์ธ ๊ฒฝ์šฐ MemberโžกLocker ์ฒ˜๋Ÿผ, ์ฃผ ํ…Œ์ด๋ธ”(PK)์—์„œ ํƒ€๊ฒŸ ํ…Œ์ด๋ธ”(FK)๋กœ ์ฐธ์กฐ๋Š” ๊ฐ€๋Šฅํ•˜๋‹ค.

PK๋ฅผ ๊ฐ€์ง„ ์ฃผ ํ…Œ์ด๋ธ”์ธ Member๊ฐ€ ์™ธ๋ž˜ํ‚ค๋ฅผ ๊ด€๋ฆฌํ•˜๋Š”๊ฑด ๊ฐ€๋Šฅํ•˜๋‹ค.

 

ํ•˜์ง€๋งŒ ๋ฐ˜๋Œ€์˜ ๊ฒฝ์šฐ๋Š” JPA์—์„œ ์ง€์›ํ•ด์ฃผ์ง€ ์•Š๋Š”๋‹ค. DB ๊ตฌ์กฐ์ƒ ๋ถˆ๊ฐ€๋Šฅํ•˜๋‹ˆ๊นŒ.

๋ถˆ๊ฐ€๋Šฅ. Locker๊ฐ€ FK๋ฅผ ์ด์šฉํ•ด Member์˜ ์™ธ๋ž˜ํ‚ค๋ฅผ ๋ณ€๊ฒฝํ•˜๋Š” ๊ฑด DB ๊ตฌ์กฐ์ƒ ๋ถˆ๊ฐ€๋Šฅํ•˜๋‹ค.

 

 

ํ•„์š”ํ•˜๋‹ค๋ฉด ์–‘๋ฐฉํ–ฅ์œผ๋กœ ์‚ฌ์šฉํ•˜์ž. ๋‹ค๋งŒ ์–‘๋ฐฉํ–ฅ์ผ ๋•Œ์—๋Š” DB์— ์™ธ๋ž˜ํ‚ค๋Š” ์–ด๋””์— ๋‘ฌ์•ผํ•˜๋Š”๊ฐ€? ๋Š” ๊ณ ๋ฏผ๊ฑฐ๋ฆฌ์ด๊ธด ํ•˜๋‹ค.

  • ๊ฐ์ฒด์ง€ํ–ฅ์ ์œผ๋กœ ์ƒ๊ฐํ•ด๋ณด๋ฉด, Member๊ฐ€ ์™ธ๋ž˜ํ‚ค๋ฅผ ๊ฐ€์ง€๊ณ ์žˆ๋Š”๊ฒŒ ์‚ฌ์šฉํ•˜๊ธฐ๋„ ํŽธํ•˜๊ณ  ์„ฑ๋Šฅ์ ์œผ๋กœ ์œ ๋ฆฌํ•˜๋‹ค.
  • ํ•˜์ง€๋งŒ ์žฅ๊ธฐ์ ์ธ ๊ด€์ ์—์„œ [ ํ•˜๋‚˜์˜ Locker๊ฐ€ ์—ฌ๋Ÿฌ๊ฐœ์˜ Member๋ฅผ ๊ฐ€์งˆ ์ˆ˜๋„ ์žˆ๋‹ค ]๋Š”๊ฒŒ ์ถ”๊ฐ€ ๋  ์ˆ˜ ์žˆ์Œ์„ ๊ณ ๋ คํ•˜๋ฉด Locker๊ฐ€ ์™ธ๋ž˜ํ‚ค๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ๋Š”๊ฒŒ DB๋ฅผ ์œ ์—ฐํ•˜๊ฒŒ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

๋‘˜ ๋‹ค ์žฅ๋‹จ์ ์ด ์žˆ๊ธดํ•˜๋‹ค. ํฌ๊ฒŒ ์ค‘์š”ํ•˜์ง€ ์•Š๋‹ค๋ฉด [ ์ฃผ ํ…Œ์ด๋ธ”์ด ์™ธ๋ž˜ํ‚ค๋ฅผ ๊ด€๋ฆฌ ] ํ•˜๋Š”๊ฒŒ ๊ฐœ๋ฐœํ•˜๊ธฐ ํŽธํ•˜๋‹ค.

 

์žฅ๋‹จ์ ์„ ์ •๋ฆฌํ•ด๋ณด๋ฉด ์•„๋ž˜์™€ ๊ฐ™๋‹ค.

  • ์ฃผ ํ…Œ์ด๋ธ”์— ์™ธ๋ž˜ํ‚ค (๊ฐœ๋ฐœ์ž๊ฐ€ ์„ ํ˜ธ)
    ์žฅ์  : ๊ฐ์ฒด์ง€ํ–ฅ์ ์œผ๋กœ ๊ฐœ๋ฐœํ•˜๊ธฐ ์ข‹๋‹ค. ์ฃผ ํ…Œ์ด๋ธ”๋งŒ ์กฐํšŒํ•ด๋„ ํƒ€๊ฒŸ ํ…Œ์ด๋ธ”์— ๋ฐ์ดํ„ฐ๊ฐ€ ์žˆ๋Š”์ง€ ํ™•์ธ ๊ฐ€๋Šฅํ•˜๋‹ค.
    ๋‹จ์  : ๊ฐ’์ด ์—†๋‹ค๋ฉด ์™ธ๋ž˜ ํ‚ค์— null์ด ๋“ค์–ด๊ฐˆ ์ˆ˜ ์žˆ๋‹ค. ( Member๋Š” Locker๊ฐ€ ์—†์„ ์ˆ˜๋„ ์žˆ๋‹ค. Locker= null)

  • ํƒ€๊ฒŸ ํ…Œ์ด๋ธ”์— ์™ธ๋ž˜ํ‚ค (DBA๊ฐ€ ์„ ํ˜ธ)
    ์žฅ์  : ํ…Œ์ด๋ธ”๊ฐ„์˜ ๊ด€๊ณ„๋ฅผ ๋ณ€๊ฒฝํ•  ๋•Œ DB ํ…Œ์ด๋ธ” ๊ตฌ์กฐ๋ฅผ ๋ณ€๊ฒฝํ•  ํ•„์š”๊ฐ€ ์—†๋‹ค. (์œ ์—ฐํ•˜๋‹ค.)
    ๋‹จ์  : ํ”„๋ก์‹œ ๊ธฐ๋Šฅ์˜ ํ•œ๊ณ„๋กœ, Lazy Loading์œผ๋กœ ์„ค์ •ํ•ด๋„ ํ•ญ์ƒ ์ฆ‰์‹œ๋กœ๋”ฉ ๋œ๋‹ค. ( Locker๋Š” Member๊ฐ€ ๋ฐ˜๋“œ์‹œ ์žˆ์–ด์•ผํ•œ๋‹ค. ์ฆ‰ ๋Œ€์ƒ ํ…Œ์ด๋ธ”์— ์ฟผ๋ฆฌ๋ฅผ ๋‚ ๋ ค ์กด์žฌ์—ฌ๋ถ€๋ฅผ ํ™•์ธํ•ด์•ผ ํ•˜๋‹ˆ ์ง€์—ฐ๋กœ๋”ฉ์ด ๋ถˆ๊ฐ€๋Šฅ )

 

 

๐Ÿ“Œ ManyToMany

๋‹ค๋Œ€๋‹ค ๊ด€๊ณ„๋Š” ๋ง˜ ํŽธํ•˜๊ฒŒ ๋“ค์œผ๋ฉด ๋œ๋‹ค. ๊ฑฐ์˜ ์‚ฌ์šฉํ•  ์ผ ์—†๋‹ค.

DB๋ฅผ ๊ณต๋ถ€ํ•ด๋ดค์œผ๋ฉด ์•Œ๊ฒ ์ง€๋งŒ. N:N๊ด€๊ณ„๋Š” ์ •๊ทœํ™”๋ฅผ ์ด์šฉํ•ด ํ…Œ์ด๋ธ”์„ ๋งŒ๋“ค์–ด 1:N N:1 ๊ด€๊ณ„๋กœ ๋ฐ”๊พธ๋Š”๊ฒŒ ๋งž๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.

 

๋‹ค๋งŒ DB์—์„œ ๊ฐ€๋Šฅํ•œ๊ฒŒ JPA์—์„œ ๋ถˆ๊ฐ€๋Šฅํ•˜๋ฉด ์ด์ƒํ•˜๋ฏ€๋กœ, ์ง€์›์€ ํ•ด์ค€๋‹ค.

JPA์—์„œ N:N ๊ด€๊ณ„๋Š” ์ค‘๊ฐ„์— ์ˆจ๊ฒจ์ง„ ์กฐ์ธํ…Œ์ด๋ธ”์„ ๋งŒ๋“ค์–ด์„œ ๊ด€๋ฆฌํ•œ๋‹ค.

๊นŒ๋จน์—ˆ์„๊นŒ๋ด ๋‹ค์‹œ ๋ณด์—ฌ์ฃผ๋Š” ERD ๊ทธ๋ฆฌ๋Š” ๋ฐฉ๋ฒ•
์ปฌ๋ ‰์…˜์€ ๋ฐ”๋กœ ์กฐํšŒํ•˜๊ณ , ์‹ค์ œ DB๋Š” ์ˆจ๊ฒจ์ง„ ์กฐ์ธํ…Œ์ด๋ธ”์„ ์ด์šฉํ•œ๋‹ค.

@Entity
public class Member{

    @ManyToMany
    @JoinTable(name = "MEMBER_PRODUCT") // ์กฐ์ธํ…Œ์ด๋ธ” ์ด๋ฆ„์„ ์ ์–ด์ค€๋‹ค.
    private List<Product> products = new ArrayList<>();
}
@Entity
public class Product {

    @Id
    @GeneratedValue
    private Long id;
    
    @ManyToMany(mappedBy = "product")
    private List<Product> members = new ArrayList<>();

}

 

ํ•˜์ง€๋งŒ ์ด๋ ‡๊ฒŒ ์ˆจ๊ฒจ์ง„ ์กฐ์ธํ…Œ์ด๋ธ”์„ ์‚ฌ์šฉํ•  ์ด์œ ๋„ ์—†๊ณ , ์‹ค์ œ๋กœ ์‚ฌ์šฉํ•  ์ผ๋„ ์—†๋‹ค.

ManyToMany ๊ด€๊ณ„๋Š” ์•„๋ž˜์™€ ๊ฐ™์ด ์•„์˜ˆ ์ƒˆ๋กœ์šด Entity๋ฅผ ๋งŒ๋“ค์–ด์„œ 1:N, N:1 ๊ด€๊ณ„๋กœ ๋ณ€๊ฒฝํ•˜๋„๋ก ํ•˜์ž.

์•„๋ž˜์ฒ˜๋Ÿผ ์ค‘๊ฐ„ ํ…Œ์ด๋ธ”์˜ ํ‚ค๋ฅผ [Member + Product]๋กœ ์‚ฌ์šฉํ•˜๊ธฐ ๋ณด๋‹ค๋Š” ๋ณ„๋„์˜ id๋ฅผ ๊ฐ€์ง€๋Š”๊ฒŒ ๋น„์ฆˆ๋‹ˆ์Šค์ ์œผ๋กœ ์œ ์—ฐํ•˜๋‹ค.

@Entity
public class MemberProduct {

    @Id
    @GeneratedValue
    private Long id; // ์ด๋ ‡๊ฒŒ PK๋ฅผ ๋”ฐ๋กœ ๊ฐ€์ง€๊ณ  ์žˆ๋Š”๊ฒŒ ์œ ์—ฐํ•œ ๊ฐœ๋ฐœ์ด ๊ฐ€๋Šฅํ•˜๋‹ค.

    @ManyToOne
    @JoinColumn(name = "MEMBER_ID")
    private Member member;

    @OneToMany
    @JoinColumn(name = "PRODUCT_ID")
    private Product product;

    private LocalDateTime orderDateTime;
    //...
}

 

๐Ÿ“Œ ๋ชจ๋“  ์—ฐ๊ด€๊ด€๊ณ„ ์‚ฌ์šฉํ•ด๋ณด๊ธฐ

๋น„์ฆˆ๋‹ˆ์Šค๋ฅผ ์•„๋ž˜์™€ ๊ฐ™์ด ๊ตฌํ˜„ํ•œ๋‹ค๊ณ  ํ•  ๋•Œ

์‹ค์ œ ํ…Œ์ด๋ธ”๊ณผ ์—”ํ‹ฐํ‹ฐ๋Š” ์•„๋ž˜์™€ ๊ฐ™๋‹ค. ๊ทธ๋ฆผ์„ ์ฐธ์กฐํ•ด์„œ ์ง์ ‘ ๋งŒ๋“ค์–ด๋ณด๋„๋ก ํ•˜์ž.

๋ธ”๋กœ๊ทธ์˜ ์ •๋ณด

JiwonDev

JiwonDev

ํ™œ๋™ํ•˜๊ธฐ