[{"data":1,"prerenderedAt":1187},["ShallowReactive",2],{"post-document:\u002Fjava\u002Fspring\u002F2026\u002F08\u002F18\u002Fjpa-relationship-mapping\u002F":3},{"id":4,"title":5,"body":6,"categories":1164,"date":1166,"description":1167,"extension":1168,"image":1169,"key_concepts":1169,"last_modified_at":1169,"legacyPath":1170,"meta":1171,"navigation":346,"part":1173,"path":1174,"published":346,"robots":1169,"seo":1175,"series":1176,"stem":1177,"strengths":1169,"summary":1169,"tags":1178,"tradeoffs":1169,"__hash__":1186},"posts\u002Fposts\u002FBackend\u002FSPRING\u002FSpring\u002F2026-08-18-jpa-relationship-mapping.md","Spring 기초 Part 6: JPA 연관관계 매핑",{"type":7,"value":8,"toc":1149},"minimark",[9,13,20,23,40,43,51,54,57,62,186,188,192,280,283,289,292,294,298,301,307,314,320,325,400,404,504,539,542,557,559,563,569,642,645,660,663,669,671,675,688,695,701,721,730,745,757,771,775,778,784,793,802,824,827,836,838,842,845,900,909,915,918,920,924,927,940,946,949,952,955,957,968,972,975,989,992,997,1000,1014,1017,1019,1023,1112,1123,1127,1145],[10,11,5],"h2",{"id":12},"spring-기초-part-6-jpa-연관관계-매핑",[14,15,16],"blockquote",{},[17,18,19],"p",{},"연관관계 매핑은 자바 객체의 참조와 데이터베이스 테이블의 외래키를 연결하는 작업이다.",[17,21,22],{},"자바 객체는 다른 객체를 필드로 참조한다.",[24,25,30],"pre",{"className":26,"code":27,"language":28,"meta":29,"style":29},"language-java shiki shiki-themes github-light github-dark","member.getTeam();\n","java","",[31,32,33],"code",{"__ignoreMap":29},[34,35,38],"span",{"class":36,"line":37},"line",1,[34,39,27],{},[17,41,42],{},"관계형 데이터베이스는 외래키로 다른 테이블을 참조한다.",[24,44,49],{"className":45,"code":47,"language":48,"meta":29},[46],"language-text","members.team_id → teams.id\n","text",[31,50,47],{"__ignoreMap":29},[17,52,53],{},"JPA는 이 두 관계를 어노테이션으로 연결한다.",[55,56],"hr",{},[58,59,61],"h3",{"id":60},"_1-먼저-알아둘-단어","1. 먼저 알아둘 단어",[63,64,65,81],"table",{},[66,67,68],"thead",{},[69,70,71,75,78],"tr",{},[72,73,74],"th",{},"용어",[72,76,77],{},"정의",[72,79,80],{},"쉬운 설명",[82,83,84,98,111,122,133,147,160,175],"tbody",{},[69,85,86,90,93],{},[87,88,89],"td",{},"기본키(PK)",[87,91,92],{},"테이블의 각 행을 유일하게 구분하는 값",[87,94,95],{},[31,96,97],{},"teams.id",[69,99,100,103,106],{},[87,101,102],{},"외래키(FK)",[87,104,105],{},"다른 테이블의 기본키를 참조하는 컬럼",[87,107,108],{},[31,109,110],{},"members.team_id",[69,112,113,116,119],{},[87,114,115],{},"연관관계",[87,117,118],{},"한 객체나 테이블이 다른 대상과 연결된 관계",[87,120,121],{},"회원이 팀에 소속됨",[69,123,124,127,130],{},[87,125,126],{},"다중성",[87,128,129],{},"관계에 참여하는 대상의 수",[87,131,132],{},"일대일, 일대다, 다대일, 다대다",[69,134,135,138,141],{},[87,136,137],{},"방향성",[87,139,140],{},"객체에서 어느 방향으로 참조할 수 있는지 나타내는 것",[87,142,143,146],{},[31,144,145],{},"Member → Team",", 또는 양쪽 모두",[69,148,149,152,155],{},[87,150,151],{},"연관관계의 주인",[87,153,154],{},"외래키 값을 실제로 저장하고 변경하는 쪽",[87,156,157],{},[31,158,159],{},"Member.team",[69,161,162,167,170],{},[87,163,164],{},[31,165,166],{},"mappedBy",[87,168,169],{},"주인이 아닌 쪽에서 주인 필드의 이름을 지정하는 속성",[87,171,172],{},[31,173,174],{},"mappedBy = \"team\"",[69,176,177,180,183],{},[87,178,179],{},"Join",[87,181,182],{},"외래키를 기준으로 여러 테이블의 데이터를 연결하는 것",[87,184,185],{},"회원과 팀을 함께 조회",[55,187],{},[58,189,191],{"id":190},"_2-연관관계의-종류","2. 연관관계의 종류",[63,193,194,207],{},[66,195,196],{},[69,197,198,201,204],{},[72,199,200],{},"어노테이션",[72,202,203],{},"관계",[72,205,206],{},"예시",[82,208,209,222,235,248,261],{},[69,210,211,216,219],{},[87,212,213],{},[31,214,215],{},"@OneToOne",[87,217,218],{},"일대일(1:1)",[87,220,221],{},"사용자와 프로필",[69,223,224,229,232],{},[87,225,226],{},[31,227,228],{},"@OneToMany",[87,230,231],{},"일대다(1:N)",[87,233,234],{},"하나의 팀과 여러 회원",[69,236,237,242,245],{},[87,238,239],{},[31,240,241],{},"@ManyToOne",[87,243,244],{},"다대일(N:1)",[87,246,247],{},"여러 회원과 하나의 팀",[69,249,250,255,258],{},[87,251,252],{},[31,253,254],{},"@ManyToMany",[87,256,257],{},"다대다(N:M)",[87,259,260],{},"여러 사용자와 여러 관심 종목",[69,262,263,268,271],{},[87,264,265],{},[31,266,267],{},"@JoinColumn",[87,269,270],{},"외래키 컬럼 지정",[87,272,273,276,277],{},[31,274,275],{},"team_id",", ",[31,278,279],{},"user_id",[17,281,282],{},"실무에서는 다대다 관계를 바로 사용하기보다 중간 Entity로 분리하는 경우가 많다.",[24,284,287],{"className":285,"code":286,"language":48,"meta":29},[46],"User 1 ─── N Watchlist N ─── 1 Stock\n",[31,288,286],{"__ignoreMap":29},[17,290,291],{},"중간 Entity를 만들면 등록 날짜, 알림 설정 같은 추가 정보도 저장할 수 있다.",[55,293],{},[58,295,297],{"id":296},"_3-다대일-단방향-매핑","3. 다대일 단방향 매핑",[17,299,300],{},"여러 회원이 하나의 팀에 소속된다고 해보자.",[24,302,305],{"className":303,"code":304,"language":48,"meta":29},[46],"Team 1  ←────  N Member\n",[31,306,304],{"__ignoreMap":29},[17,308,309,310,313],{},"외래키는 보통 다수 쪽 테이블인 ",[31,311,312],{},"members","에 둔다.",[24,315,318],{"className":316,"code":317,"language":48,"meta":29},[46],"teams                   members\n-------------           ----------------\nid (PK)       ←──────── team_id (FK)\nname                    id (PK)\n                        name\n",[31,319,317],{"__ignoreMap":29},[321,322,324],"h4",{"id":323},"team-entity","Team Entity",[24,326,328],{"className":26,"code":327,"language":28,"meta":29,"style":29},"@Entity\npublic class Team {\n\n    @Id\n    @GeneratedValue(strategy = GenerationType.IDENTITY)\n    private Long id;\n\n    private String name;\n\n    protected Team() {\n    }\n}\n",[31,329,330,335,341,348,354,360,366,371,377,382,388,394],{"__ignoreMap":29},[34,331,332],{"class":36,"line":37},[34,333,334],{},"@Entity\n",[34,336,338],{"class":36,"line":337},2,[34,339,340],{},"public class Team {\n",[34,342,344],{"class":36,"line":343},3,[34,345,347],{"emptyLinePlaceholder":346},true,"\n",[34,349,351],{"class":36,"line":350},4,[34,352,353],{},"    @Id\n",[34,355,357],{"class":36,"line":356},5,[34,358,359],{},"    @GeneratedValue(strategy = GenerationType.IDENTITY)\n",[34,361,363],{"class":36,"line":362},6,[34,364,365],{},"    private Long id;\n",[34,367,369],{"class":36,"line":368},7,[34,370,347],{"emptyLinePlaceholder":346},[34,372,374],{"class":36,"line":373},8,[34,375,376],{},"    private String name;\n",[34,378,380],{"class":36,"line":379},9,[34,381,347],{"emptyLinePlaceholder":346},[34,383,385],{"class":36,"line":384},10,[34,386,387],{},"    protected Team() {\n",[34,389,391],{"class":36,"line":390},11,[34,392,393],{},"    }\n",[34,395,397],{"class":36,"line":396},12,[34,398,399],{},"}\n",[321,401,403],{"id":402},"member-entity","Member Entity",[24,405,407],{"className":26,"code":406,"language":28,"meta":29,"style":29},"@Entity\npublic class Member {\n\n    @Id\n    @GeneratedValue(strategy = GenerationType.IDENTITY)\n    private Long id;\n\n    private String name;\n\n    @ManyToOne(fetch = FetchType.LAZY)\n    @JoinColumn(name = \"team_id\")\n    private Team team;\n\n    protected Member() {\n    }\n\n    public void changeTeam(Team team) {\n        this.team = team;\n    }\n}\n",[31,408,409,413,418,422,426,430,434,438,442,446,451,456,461,466,472,477,482,488,494,499],{"__ignoreMap":29},[34,410,411],{"class":36,"line":37},[34,412,334],{},[34,414,415],{"class":36,"line":337},[34,416,417],{},"public class Member {\n",[34,419,420],{"class":36,"line":343},[34,421,347],{"emptyLinePlaceholder":346},[34,423,424],{"class":36,"line":350},[34,425,353],{},[34,427,428],{"class":36,"line":356},[34,429,359],{},[34,431,432],{"class":36,"line":362},[34,433,365],{},[34,435,436],{"class":36,"line":368},[34,437,347],{"emptyLinePlaceholder":346},[34,439,440],{"class":36,"line":373},[34,441,376],{},[34,443,444],{"class":36,"line":379},[34,445,347],{"emptyLinePlaceholder":346},[34,447,448],{"class":36,"line":384},[34,449,450],{},"    @ManyToOne(fetch = FetchType.LAZY)\n",[34,452,453],{"class":36,"line":390},[34,454,455],{},"    @JoinColumn(name = \"team_id\")\n",[34,457,458],{"class":36,"line":396},[34,459,460],{},"    private Team team;\n",[34,462,464],{"class":36,"line":463},13,[34,465,347],{"emptyLinePlaceholder":346},[34,467,469],{"class":36,"line":468},14,[34,470,471],{},"    protected Member() {\n",[34,473,475],{"class":36,"line":474},15,[34,476,393],{},[34,478,480],{"class":36,"line":479},16,[34,481,347],{"emptyLinePlaceholder":346},[34,483,485],{"class":36,"line":484},17,[34,486,487],{},"    public void changeTeam(Team team) {\n",[34,489,491],{"class":36,"line":490},18,[34,492,493],{},"        this.team = team;\n",[34,495,497],{"class":36,"line":496},19,[34,498,393],{},[34,500,502],{"class":36,"line":501},20,[34,503,399],{},[505,506,507,521,530],"ul",{},[508,509,510,512,513,516,517,520],"li",{},[31,511,241],{},": 여러 ",[31,514,515],{},"Member","가 하나의 ",[31,518,519],{},"Team","과 연결된다.",[508,522,523,526,527,529],{},[31,524,525],{},"@JoinColumn(name = \"team_id\")",": ",[31,528,110],{},"를 외래키로 사용한다.",[508,531,532,526,535,538],{},[31,533,534],{},"FetchType.LAZY",[31,536,537],{},"team","이 실제로 필요할 때 조회하도록 설정한다.",[17,540,541],{},"현재는 Member만 Team을 참조하므로 단방향 관계다.",[24,543,545],{"className":26,"code":544,"language":28,"meta":29,"style":29},"member.getTeam();  \u002F\u002F 가능\nteam.getMembers(); \u002F\u002F Team에 members 필드가 없으므로 불가능\n",[31,546,547,552],{"__ignoreMap":29},[34,548,549],{"class":36,"line":37},[34,550,551],{},"member.getTeam();  \u002F\u002F 가능\n",[34,553,554],{"class":36,"line":337},[34,555,556],{},"team.getMembers(); \u002F\u002F Team에 members 필드가 없으므로 불가능\n",[55,558],{},[58,560,562],{"id":561},"_4-양방향-연관관계","4. 양방향 연관관계",[17,564,565,566,568],{},"Team에서도 소속 회원 목록을 조회하고 싶다면 ",[31,567,228],{},"를 추가한다.",[24,570,572],{"className":26,"code":571,"language":28,"meta":29,"style":29},"@Entity\npublic class Team {\n\n    @Id\n    @GeneratedValue(strategy = GenerationType.IDENTITY)\n    private Long id;\n\n    private String name;\n\n    @OneToMany(mappedBy = \"team\")\n    private List\u003CMember> members = new ArrayList\u003C>();\n\n    public List\u003CMember> getMembers() {\n        return members;\n    }\n}\n",[31,573,574,578,582,586,590,594,598,602,606,610,615,620,624,629,634,638],{"__ignoreMap":29},[34,575,576],{"class":36,"line":37},[34,577,334],{},[34,579,580],{"class":36,"line":337},[34,581,340],{},[34,583,584],{"class":36,"line":343},[34,585,347],{"emptyLinePlaceholder":346},[34,587,588],{"class":36,"line":350},[34,589,353],{},[34,591,592],{"class":36,"line":356},[34,593,359],{},[34,595,596],{"class":36,"line":362},[34,597,365],{},[34,599,600],{"class":36,"line":368},[34,601,347],{"emptyLinePlaceholder":346},[34,603,604],{"class":36,"line":373},[34,605,376],{},[34,607,608],{"class":36,"line":379},[34,609,347],{"emptyLinePlaceholder":346},[34,611,612],{"class":36,"line":384},[34,613,614],{},"    @OneToMany(mappedBy = \"team\")\n",[34,616,617],{"class":36,"line":390},[34,618,619],{},"    private List\u003CMember> members = new ArrayList\u003C>();\n",[34,621,622],{"class":36,"line":396},[34,623,347],{"emptyLinePlaceholder":346},[34,625,626],{"class":36,"line":463},[34,627,628],{},"    public List\u003CMember> getMembers() {\n",[34,630,631],{"class":36,"line":468},[34,632,633],{},"        return members;\n",[34,635,636],{"class":36,"line":474},[34,637,393],{},[34,639,640],{"class":36,"line":479},[34,641,399],{},[17,643,644],{},"이제 객체에서 양쪽 방향으로 이동할 수 있다.",[24,646,648],{"className":26,"code":647,"language":28,"meta":29,"style":29},"member.getTeam();  \u002F\u002F Member → Team\nteam.getMembers(); \u002F\u002F Team → Member\n",[31,649,650,655],{"__ignoreMap":29},[34,651,652],{"class":36,"line":37},[34,653,654],{},"member.getTeam();  \u002F\u002F Member → Team\n",[34,656,657],{"class":36,"line":337},[34,658,659],{},"team.getMembers(); \u002F\u002F Team → Member\n",[17,661,662],{},"양방향 객체 관계라고 해서 DB 외래키가 두 개 생기는 것은 아니다.",[24,664,667],{"className":665,"code":666,"language":48,"meta":29},[46],"객체: Member ↔ Team\nDB:   members.team_id → teams.id\n",[31,668,666],{"__ignoreMap":29},[55,670],{},[58,672,674],{"id":673},"_5-연관관계의-주인","5. 연관관계의 주인",[17,676,677,678,680,681,684,685,687],{},"객체에는 ",[31,679,159],{},"과 ",[31,682,683],{},"Team.members","라는 참조가 두 개지만, DB 외래키는 ",[31,686,110],{}," 하나다.",[17,689,690,691,694],{},"따라서 JPA는 어느 필드의 값을 기준으로 외래키를 변경할지 결정해야 한다. 외래키를 관리하는 쪽을 ",[692,693,151],"strong",{},"이라고 한다.",[17,696,697,698,700],{},"이 예제에서는 ",[31,699,159],{},"이 주인이다.",[24,702,704],{"className":26,"code":703,"language":28,"meta":29,"style":29},"@ManyToOne(fetch = FetchType.LAZY)\n@JoinColumn(name = \"team_id\")\nprivate Team team;\n",[31,705,706,711,716],{"__ignoreMap":29},[34,707,708],{"class":36,"line":37},[34,709,710],{},"@ManyToOne(fetch = FetchType.LAZY)\n",[34,712,713],{"class":36,"line":337},[34,714,715],{},"@JoinColumn(name = \"team_id\")\n",[34,717,718],{"class":36,"line":343},[34,719,720],{},"private Team team;\n",[17,722,723,724,726,727,729],{},"주인이 아닌 ",[31,725,683],{},"에는 ",[31,728,166],{},"를 작성한다.",[24,731,733],{"className":26,"code":732,"language":28,"meta":29,"style":29},"@OneToMany(mappedBy = \"team\")\nprivate List\u003CMember> members = new ArrayList\u003C>();\n",[31,734,735,740],{"__ignoreMap":29},[34,736,737],{"class":36,"line":37},[34,738,739],{},"@OneToMany(mappedBy = \"team\")\n",[34,741,742],{"class":36,"line":337},[34,743,744],{},"private List\u003CMember> members = new ArrayList\u003C>();\n",[17,746,747,749,750,752,753,756],{},[31,748,174],{},"의 ",[31,751,537],{},"은 DB 컬럼명이 아니라 ",[692,754,755],{},"Member 클래스의 필드명","이다.",[24,758,760],{"className":26,"code":759,"language":28,"meta":29,"style":29},"private Team team;\n             \u002F\u002F ↑ 이 필드명\n",[31,761,762,766],{"__ignoreMap":29},[34,763,764],{"class":36,"line":37},[34,765,720],{},[34,767,768],{"class":36,"line":337},[34,769,770],{},"             \u002F\u002F ↑ 이 필드명\n",[321,772,774],{"id":773},"외래키를-변경한다는-뜻","외래키를 변경한다는 뜻",[17,776,777],{},"외래키를 변경한다는 것은 객체의 소속 관계를 바꾼다는 뜻이다.",[24,779,782],{"className":780,"code":781,"language":48,"meta":29},[46],"변경 전: members.team_id = 1\n변경 후: members.team_id = 2\n",[31,783,781],{"__ignoreMap":29},[24,785,787],{"className":26,"code":786,"language":28,"meta":29,"style":29},"member.changeTeam(team2);\n",[31,788,789],{"__ignoreMap":29},[34,790,791],{"class":36,"line":37},[34,792,786],{},[17,794,795,796,798,799,801],{},"JPA는 주인인 ",[31,797,159],{},"의 변경을 기준으로 ",[31,800,275],{},"를 수정한다.",[24,803,807],{"className":804,"code":805,"language":806,"meta":29,"style":29},"language-sql shiki shiki-themes github-light github-dark","UPDATE members\nSET team_id = 2\nWHERE id = 1;\n","sql",[31,808,809,814,819],{"__ignoreMap":29},[34,810,811],{"class":36,"line":37},[34,812,813],{},"UPDATE members\n",[34,815,816],{"class":36,"line":337},[34,817,818],{},"SET team_id = 2\n",[34,820,821],{"class":36,"line":343},[34,822,823],{},"WHERE id = 1;\n",[17,825,826],{},"반대편 컬렉션만 변경하면 메모리의 목록은 바뀌지만 외래키 변경이 반영되지 않을 수 있다.",[24,828,830],{"className":26,"code":829,"language":28,"meta":29,"style":29},"team.getMembers().add(member); \u002F\u002F 이것만으로는 부족함\n",[31,831,832],{"__ignoreMap":29},[34,833,834],{"class":36,"line":37},[34,835,829],{},[55,837],{},[58,839,841],{"id":840},"_6-양쪽-객체를-함께-변경하기","6. 양쪽 객체를 함께 변경하기",[17,843,844],{},"DB 외래키는 주인 쪽 값으로 변경되지만, 현재 메모리의 두 객체도 일치시키는 것이 안전하다.",[24,846,848],{"className":26,"code":847,"language":28,"meta":29,"style":29},"public void changeTeam(Team newTeam) {\n    if (this.team != null) {\n        this.team.getMembers().remove(this);\n    }\n\n    this.team = newTeam;\n\n    if (newTeam != null) {\n        newTeam.getMembers().add(this);\n    }\n}\n",[31,849,850,855,860,865,869,873,878,882,887,892,896],{"__ignoreMap":29},[34,851,852],{"class":36,"line":37},[34,853,854],{},"public void changeTeam(Team newTeam) {\n",[34,856,857],{"class":36,"line":337},[34,858,859],{},"    if (this.team != null) {\n",[34,861,862],{"class":36,"line":343},[34,863,864],{},"        this.team.getMembers().remove(this);\n",[34,866,867],{"class":36,"line":350},[34,868,393],{},[34,870,871],{"class":36,"line":356},[34,872,347],{"emptyLinePlaceholder":346},[34,874,875],{"class":36,"line":362},[34,876,877],{},"    this.team = newTeam;\n",[34,879,880],{"class":36,"line":368},[34,881,347],{"emptyLinePlaceholder":346},[34,883,884],{"class":36,"line":373},[34,885,886],{},"    if (newTeam != null) {\n",[34,888,889],{"class":36,"line":379},[34,890,891],{},"        newTeam.getMembers().add(this);\n",[34,893,894],{"class":36,"line":384},[34,895,393],{},[34,897,898],{"class":36,"line":390},[34,899,399],{},[24,901,903],{"className":26,"code":902,"language":28,"meta":29,"style":29},"member.changeTeam(team);\n",[31,904,905],{"__ignoreMap":29},[34,906,907],{"class":36,"line":37},[34,908,902],{},[24,910,913],{"className":911,"code":912,"language":48,"meta":29},[46],"Member.team에 Team 저장\n          ↓\nTeam.members에 Member 추가\n          ↓\n메모리의 양쪽 관계 일치\n          ↓\nmembers.team_id 변경\n",[31,914,912],{"__ignoreMap":29},[17,916,917],{},"이런 메서드를 연관관계 편의 메서드라고 한다. 양쪽 메서드가 서로를 계속 호출하면 무한 호출이 발생할 수 있으므로 한쪽에서 관계를 관리한다.",[55,919],{},[58,921,923],{"id":922},"_7-지연-로딩","7. 지연 로딩",[17,925,926],{},"지연 로딩(Lazy Loading)은 연관된 Entity를 처음부터 조회하지 않고 실제로 사용할 때 조회하는 방식이다.",[24,928,930],{"className":26,"code":929,"language":28,"meta":29,"style":29},"@ManyToOne(fetch = FetchType.LAZY)\nprivate Team team;\n",[31,931,932,936],{"__ignoreMap":29},[34,933,934],{"class":36,"line":37},[34,935,710],{},[34,937,938],{"class":36,"line":337},[34,939,720],{},[24,941,944],{"className":942,"code":943,"language":48,"meta":29},[46],"Member 조회\n    ↓\nTeam은 아직 조회하지 않음\n    ↓\nmember.getTeam() 사용\n    ↓\n필요한 Team 조회\n",[31,945,943],{"__ignoreMap":29},[17,947,948],{},"즉시 로딩(Eager Loading)은 원래 Entity를 조회할 때 연관된 Entity도 함께 조회한다.",[17,950,951],{},"연관관계를 무조건 즉시 로딩하면 예상하지 못한 SQL이 많이 실행될 수 있으므로 일반적으로 지연 로딩을 우선 사용하고, 필요한 조회에서 fetch join이나 EntityGraph 등을 명시적으로 고려한다.",[17,953,954],{},"지연 로딩된 Entity를 영속성 컨텍스트가 끝난 뒤 접근하면 예외가 발생할 수 있으므로 Service 안에서 필요한 데이터를 DTO로 변환하는 방식이 안전하다.",[55,956],{},[58,958,960,961,964,965],{"id":959},"_8-cascade와-orphanremoval","8. ",[31,962,963],{},"cascade","와 ",[31,966,967],{},"orphanRemoval",[321,969,970],{"id":963},[31,971,963],{},[17,973,974],{},"영속성 전이(Cascade)는 부모 Entity의 저장이나 삭제 작업을 연관된 Entity에도 전달한다.",[24,976,978],{"className":26,"code":977,"language":28,"meta":29,"style":29},"@OneToMany(mappedBy = \"team\", cascade = CascadeType.ALL)\nprivate List\u003CMember> members = new ArrayList\u003C>();\n",[31,979,980,985],{"__ignoreMap":29},[34,981,982],{"class":36,"line":37},[34,983,984],{},"@OneToMany(mappedBy = \"team\", cascade = CascadeType.ALL)\n",[34,986,987],{"class":36,"line":337},[34,988,744],{},[17,990,991],{},"연관되어 있다는 이유만으로 무조건 사용하면 안 된다. 두 Entity의 생명주기를 함께 관리할 때 사용한다.",[321,993,995],{"id":994},"orphanremoval",[31,996,967],{},[17,998,999],{},"고아 객체 제거는 부모 컬렉션에서 제거된 자식 Entity를 DB에서도 삭제하는 기능이다.",[24,1001,1003],{"className":26,"code":1002,"language":28,"meta":29,"style":29},"@OneToMany(mappedBy = \"team\", orphanRemoval = true)\nprivate List\u003CMember> members = new ArrayList\u003C>();\n",[31,1004,1005,1010],{"__ignoreMap":29},[34,1006,1007],{"class":36,"line":37},[34,1008,1009],{},"@OneToMany(mappedBy = \"team\", orphanRemoval = true)\n",[34,1011,1012],{"class":36,"line":337},[34,1013,744],{},[17,1015,1016],{},"단순히 관계만 끊으려는 상황에서도 데이터가 삭제될 수 있으므로 주의해야 한다.",[55,1018],{},[58,1020,1022],{"id":1021},"핵심-정리","핵심 정리",[63,1024,1025,1035],{},[66,1026,1027],{},[69,1028,1029,1032],{},[72,1030,1031],{},"개념",[72,1033,1034],{},"한 줄 정리",[82,1036,1037,1045,1064,1071,1077,1086,1094,1103],{},[69,1038,1039,1042],{},[87,1040,1041],{},"연관관계 매핑",[87,1043,1044],{},"객체 참조와 테이블 외래키를 연결",[69,1046,1047,1049],{},[87,1048,126],{},[87,1050,1051,276,1054,276,1057,276,1060,1063],{},[31,1052,1053],{},"1:1",[31,1055,1056],{},"1:N",[31,1058,1059],{},"N:1",[31,1061,1062],{},"N:M","처럼 관계의 수를 표현",[69,1065,1066,1068],{},[87,1067,137],{},[87,1069,1070],{},"객체가 한쪽 또는 양쪽으로 참조할 수 있는지 표현",[69,1072,1073,1075],{},[87,1074,151],{},[87,1076,154],{},[69,1078,1079,1083],{},[87,1080,1081],{},[31,1082,166],{},[87,1084,1085],{},"주인이 아닌 쪽에서 주인 필드명을 지정",[69,1087,1088,1091],{},[87,1089,1090],{},"지연 로딩",[87,1092,1093],{},"연관 Entity가 실제로 필요할 때 조회",[69,1095,1096,1100],{},[87,1097,1098],{},[31,1099,963],{},[87,1101,1102],{},"영속성 작업을 연관 Entity에 전달",[69,1104,1105,1109],{},[87,1106,1107],{},[31,1108,967],{},[87,1110,1111],{},"관계에서 제거된 자식 Entity를 DB에서도 삭제",[14,1113,1114],{},[17,1115,1116,1117,1119,1120,1122],{},"Team과 Member의 양방향 관계에서는 외래키 ",[31,1118,275],{},"가 있는 ",[31,1121,159],{},"이 연관관계의 주인이다.",[58,1124,1126],{"id":1125},"참고-자료","참고 자료",[505,1128,1129,1138],{},[508,1130,1131],{},[1132,1133,1137],"a",{"href":1134,"rel":1135},"https:\u002F\u002Fjakarta.ee\u002Fspecifications\u002Fpersistence\u002F",[1136],"nofollow","Jakarta Persistence 공식 명세",[508,1139,1140],{},[1132,1141,1144],{"href":1142,"rel":1143},"https:\u002F\u002Fdocs.jboss.org\u002Fhibernate\u002Form\u002Fcurrent\u002Fuserguide\u002Fhtml_single\u002FHibernate_User_Guide.html",[1136],"Hibernate ORM User Guide",[1146,1147,1148],"style",{},"html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"title":29,"searchDepth":337,"depth":337,"links":1150},[1151],{"id":12,"depth":337,"text":5,"children":1152},[1153,1154,1155,1156,1157,1158,1159,1160,1162,1163],{"id":60,"depth":343,"text":61},{"id":190,"depth":343,"text":191},{"id":296,"depth":343,"text":297},{"id":561,"depth":343,"text":562},{"id":673,"depth":343,"text":674},{"id":840,"depth":343,"text":841},{"id":922,"depth":343,"text":923},{"id":959,"depth":343,"text":1161},"8. cascade와 orphanRemoval",{"id":1021,"depth":343,"text":1022},{"id":1125,"depth":343,"text":1126},[28,1165],"spring","2026-08-18 09:00:00 +0900","객체 참조와 외래키를 연결하고, 다대일, 일대다, 연관관계의 주인, mappedBy와 지연 로딩을 이해한다.","md",null,"\u002Fjava\u002Fspring\u002F2026\u002F08\u002F18\u002Fjpa-relationship-mapping\u002F",{"layout":1172},"post","6","\u002Fposts\u002Fbackend\u002Fspring\u002Fspring\u002F2026-08-18-jpa-relationship-mapping",{"title":5,"description":1167},"Spring 기초","posts\u002FBackend\u002FSPRING\u002FSpring\u002F2026-08-18-jpa-relationship-mapping",[1179,1180,1181,1182,1183,1184,1185],"Java","Spring","JPA","Relationship Mapping","ManyToOne","OneToMany","Foreign Key","igi1-5uvXOYtajr0OeAZehOvdsfqolAheezaJmoKrAw",1788744786282]