<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>PROGRAMMING</title>
    <link>https://c0mmedes.tistory.com/</link>
    <description></description>
    <language>ko</language>
    <pubDate>Thu, 9 Apr 2026 10:16:04 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>c0mmedes</managingEditor>
    <item>
      <title>[BOJ] [JAVA] [GOLD 4] 17298: 오큰수</title>
      <link>https://c0mmedes.tistory.com/171</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;a href=&quot;https://www.acmicpc.net/problem/17298&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://www.acmicpc.net/problem/17298&lt;/a&gt;&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1722583914756&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.*;

public class Main {
    static int N, A[];
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        N = Integer.parseInt(br.readLine()); // 크기
        A = new int[N];

        StringTokenizer st = new StringTokenizer(br.readLine());
        for (int i = 0; i &amp;lt; N; i++) {
            A[i] = Integer.parseInt(st.nextToken());
        }

        Stack&amp;lt;Integer&amp;gt; stack = new Stack&amp;lt;&amp;gt;();

        for (int i = 0; i &amp;lt; N; i++) {
            // 전에 있던 인덱스의 해당하는 수가 이번에 해당하는 수보다 작으면 그 자리에 넣어주기
            while(!stack.isEmpty() &amp;amp;&amp;amp; A[stack.peek()] &amp;lt; A[i]) {
                A[stack.pop()] = A[i];
            }
            // 다음 인덱스 작업을 위해 넣어주고
            stack.push(i);
        }

        // 남은 애들 처리
        while(!stack.isEmpty()) {
            A[stack.pop()] = -1;
        }

        StringBuilder sb = new StringBuilder();
        
        for (int num : A) sb.append(num + &quot; &quot;);

        System.out.println(sb);

    }
}
// 오큰수(오른쪽에 있으면서 Ai 보다 큰 수 중에서 가장 왼쪽에 있는 수, 없을 경우 -1) 구하기
// ex) A = [3, 5, 2, 7] -&amp;gt; NGE(1) = 5, NGE(2) = 7, NGE(3) = 7, NGE(4) = -1
// ex) A = [9, 5, 4, 8] -&amp;gt; NGE(1) = -1, NGE(2) = 8, NGE(3) = 8, NGE(4) = -1&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;수가 아닌 인덱스로 접근하는 것이 핵심&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;StringBuilder 중요&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>BAEKJOON/자료 구조(Data Structure)</category>
      <author>c0mmedes</author>
      <guid isPermaLink="true">https://c0mmedes.tistory.com/171</guid>
      <comments>https://c0mmedes.tistory.com/171#entry171comment</comments>
      <pubDate>Fri, 2 Aug 2024 16:33:44 +0900</pubDate>
    </item>
    <item>
      <title>[BOJ] [JAVA] [GOLD 3] 2623: 음악프로그램</title>
      <link>https://c0mmedes.tistory.com/170</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.acmicpc.net/problem/2623&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://www.acmicpc.net/problem/2623&lt;/a&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1720152262861&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Queue;
import java.util.StringTokenizer;

public class Main {
    static int N, M;
    static Node adjList[];
    static int inDegree[];
    static class Node {
        int vertex;
        Node link;

        public Node (int vertex, Node link){
            this.vertex = vertex;
            this.link = link;
        }
    }
    public static void main(String[] args) throws Exception {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        StringTokenizer st = new StringTokenizer(br.readLine());
        N = Integer.parseInt(st.nextToken()); // 가수의 수
        M = Integer.parseInt(st.nextToken()); // 보조PD의 수
        
        adjList = new Node[N+1];
        inDegree = new int[N+1]; // 진입 간선의 수 체크

        for (int m = 0; m &amp;lt; M; m++) {
            st = new StringTokenizer(br.readLine());
            int num = Integer.parseInt(st.nextToken()); // 보조PD가 담당한 가수의 수
            int temp[] = new int[num];
            for (int i = 0; i &amp;lt; num; i++) {
                temp[i] = Integer.parseInt(st.nextToken()); // 순서
            }
            for (int i = 0; i &amp;lt; num-1; i++) {
                // A -&amp;gt; B
                int A = temp[i]; // 진출 정점
                int B = temp[i+1]; // 진입 정점
                adjList[A] = new Node(B, adjList[A]);
                inDegree[B]++; // 진입 간선++
            }
        }

        ArrayList&amp;lt;Integer&amp;gt; list = topologySort();
        if(list.size() == N) {
            for (Integer vertex : list) System.out.println(vertex);
        } else {
            System.out.println(0);
        }
    }

    private static ArrayList&amp;lt;Integer&amp;gt; topologySort() {
        ArrayList&amp;lt;Integer&amp;gt; orderList = new ArrayList&amp;lt;&amp;gt;();
        Queue&amp;lt;Integer&amp;gt; q = new ArrayDeque&amp;lt;&amp;gt;();

        for (int i = 1; i &amp;lt;= N; i++) {
            if(inDegree[i] == 0) q.offer(i); // 진입 차수가 0인 애들 넣어주고
        }

        while(!q.isEmpty()) {
            int cur = q.poll();
            orderList.add(cur);

            // 현재 정점 기준으로 인접정점 정리
            for (Node node = adjList[cur]; node != null; node = node.link) {
                if(--inDegree[node.vertex] == 0) q.offer(node.vertex);
            }
        }
        return orderList;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;h2 style=&quot;color: #000000; text-align: left;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;background-color: #a6bc00; color: #ffffff;&quot;&gt;&lt;b&gt;위상 정렬&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc; color: #333333; text-align: left;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: disc; color: #000000;&quot;&gt;&lt;b&gt;유향 그래프&lt;/b&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc; color: #000000;&quot;&gt;&lt;b&gt;싸이클 존재하지 않음&lt;/b&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc; color: #000000;&quot;&gt;&lt;b&gt;방향성을 거스리지 않으면서 순서적으로 탐색&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;ul style=&quot;list-style-type: disc; color: #333333; text-align: left;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: disc; color: #000000;&quot;&gt;&lt;b&gt;메커니즘&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: disc; color: #000000;&quot;&gt;&lt;b&gt;차수 - 정점에 연결된 간선 수&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: disc; color: #000000;&quot;&gt;&lt;b&gt;진출 차수 - 자신의 정점에서 타정점으로 나가는 간선 수&lt;/b&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc; color: #000000;&quot;&gt;&lt;b&gt;진입 차수 - 타정점에서 자신의 정점으로 들어오는 간선 수&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li style=&quot;list-style-type: none; color: #000000;&quot;&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: none; color: #000000;&quot;&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: none; color: #000000;&quot;&gt;&amp;nbsp;&lt;/li&gt;
&lt;/ul&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li style=&quot;list-style-type: decimal; color: #000000;&quot;&gt;&lt;b&gt;진입 차수가 0인 노드(시작점)를 큐에 모두 넣는다.&lt;/b&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: decimal; color: #000000;&quot;&gt;&lt;b&gt;큐에서 진입 차수가 0인 노드를 꺼내어 자신과 입전한 노드의 간선을 제거한다.&lt;/b&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li style=&quot;list-style-type: decimal; color: #000000;&quot;&gt;&lt;b&gt;인접한 노드의 진입 차수를 1 감소시킨다.&lt;/b&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li style=&quot;list-style-type: decimal; color: #000000;&quot;&gt;&lt;b&gt;간선 제거 후 진입 차수가 0이 된 노드를 큐에 넣는다.&lt;/b&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: decimal; color: #000000;&quot;&gt;&lt;b&gt;큐가 공백 큐 상태가 될 때 까지 2-3 작업을 반복&lt;/b&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li style=&quot;list-style-type: decimal; color: #000000;&quot;&gt;&lt;b&gt;모든 노드가 처리되지 않았다면 사이클 발생&lt;/b&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: decimal; color: #000000;&quot;&gt;&lt;b&gt;모든 노드가 다 처리되었다면 위상 정렬 완성&lt;/b&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>BAEKJOON/그래프(Graph) 이론</category>
      <category>위상정렬</category>
      <author>c0mmedes</author>
      <guid isPermaLink="true">https://c0mmedes.tistory.com/170</guid>
      <comments>https://c0mmedes.tistory.com/170#entry170comment</comments>
      <pubDate>Fri, 5 Jul 2024 13:05:44 +0900</pubDate>
    </item>
    <item>
      <title>[BOJ] [JAVA] [GOLD 3] 2252: 줄 세우기</title>
      <link>https://c0mmedes.tistory.com/169</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;a href=&quot;https://www.acmicpc.net/problem/2252&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://www.acmicpc.net/problem/2252&lt;/a&gt;&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1719988354681&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.*;

public class BOJ2252 {
    static class Node {
        int vertex;
        Node link;
        public Node (int vertex, Node link) {
            this.vertex = vertex;
            this.link = link;
        }
    }
    static int N, M;
    static Node adjList[];
    static int inDegree[];
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        StringTokenizer st = new StringTokenizer(br.readLine());

        N = Integer.parseInt(st.nextToken()); // N명의 학생
        M = Integer.parseInt(st.nextToken()); // 키를 비교한 회수
        adjList = new Node[N+1];
        inDegree = new int[N+1]; // 진입간선의 수 체크를 위한 배열

        for (int m = 0; m &amp;lt; M; m++) {
            st = new StringTokenizer(br.readLine());
            // A가 학생 B의 앞에 서야함
            // A -&amp;gt; B 로 가는 간선
            int A = Integer.parseInt(st.nextToken()); // from, 진출 정점
            int B = Integer.parseInt(st.nextToken()); // to, 진입 정점
            adjList[A] = new Node(B, adjList[A]);
            inDegree[B]++; // 간선을 받는 B++
        }

        ArrayList&amp;lt;Integer&amp;gt; list = topologySort();
        if(list.size() == N) {
            for (Integer vertex : list) {
                System.out.print(vertex + &quot; &quot;);
            }
        } else {
            System.out.println(&quot;사이클 발생&quot;);
        }
    }

    private static ArrayList&amp;lt;Integer&amp;gt; topologySort() {
        ArrayList&amp;lt;Integer&amp;gt; orderList = new ArrayList&amp;lt;&amp;gt;();
        Queue&amp;lt;Integer&amp;gt; q = new ArrayDeque&amp;lt;&amp;gt;();
        for (int i = 1; i &amp;lt;= N; i++) {
            if(inDegree[i] == 0) q.offer(i); // 진입 차수가 0인 정점 넣기
        }

        while(!q.isEmpty()) {
            int cur = q.poll();
            orderList.add(cur);

            // 현재 정점 기준으로 인접정점 처리
            for (Node temp = adjList[cur]; temp != null; temp = temp.link) {
                if (--inDegree[temp.vertex] == 0) q.offer(temp.vertex);
            }
        }
        return orderList;
    }
}

// tc
/*
3 2
1 3
2 3
answer : 1 2 3

4 2
4 2
3 1
answer : 4 2 3 1 (답은 여러가지)
*/&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;background-color: #a6bc00; color: #ffffff;&quot;&gt;&lt;b&gt;위상 정렬&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;유향 그래프&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;싸이클 존재하지 않음&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;방향성을 거스리지 않으면서 순서적으로 탐색&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;메커니즘&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;차수 - 정점에 연결된 간선 수&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;진출 차수 - 자신의 정점에서 타정점으로 나가는 간선 수&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;진입 차수 - 타정점에서 자신의 정점으로 들어오는 간선 수&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li style=&quot;list-style-type: none;&quot;&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: none;&quot;&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: none;&quot;&gt;&amp;nbsp;&lt;/li&gt;
&lt;/ul&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;진입 차수가 0인 노드(시작점)를 큐에 모두 넣는다.&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;큐에서 진입 차수가 0인 노드를 꺼내어 자신과 입전한 노드의 간선을 제거한다.&lt;/b&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt; 인접한 노드의 진입 차수를 1 감소시킨다. &lt;/b&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;간선 제거 후 진입 차수가 0이 된 노드를 큐에 넣는다.&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;큐가 공백 큐 상태가 될 때 까지 2-3 작업을 반복&lt;/b&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;모든 노드가 처리되지 않았다면 사이클 발생&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;모든 노드가 다 처리되었다면 위상 정렬 완성&lt;/b&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>BAEKJOON/그래프(Graph) 이론</category>
      <category>위상 정렬</category>
      <author>c0mmedes</author>
      <guid isPermaLink="true">https://c0mmedes.tistory.com/169</guid>
      <comments>https://c0mmedes.tistory.com/169#entry169comment</comments>
      <pubDate>Wed, 3 Jul 2024 15:36:51 +0900</pubDate>
    </item>
    <item>
      <title>[SWEA] [JAVA] [Difficulty 4] [1249] [S/W 문제해결 응용] 4일차 - 보급로</title>
      <link>https://c0mmedes.tistory.com/168</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://swexpertacademy.com/main/code/problem/problemDetail.do?contestProbId=AV15QRX6APsCFAYD&amp;amp;&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://swexpertacademy.com/main/code/problem/problemDetail.do?contestProbId=AV15QRX6APsCFAYD&amp;amp;&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1719988155740&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;SW Expert Academy&quot; data-og-description=&quot;SW 프로그래밍 역량 강화에 도움이 되는 다양한 학습 컨텐츠를 확인하세요!&quot; data-og-host=&quot;swexpertacademy.com&quot; data-og-source-url=&quot;https://swexpertacademy.com/main/code/problem/problemDetail.do?contestProbId=AV15QRX6APsCFAYD&amp;amp;&quot; data-og-url=&quot;https://swexpertacademy.com&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bI2PwZ/hyWrXzI9Sx/7tLkmLV3TgjEEYjkxFvt71/img.png?width=600&amp;amp;height=315&amp;amp;face=0_0_600_315&quot;&gt;&lt;a href=&quot;https://swexpertacademy.com/main/code/problem/problemDetail.do?contestProbId=AV15QRX6APsCFAYD&amp;amp;&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://swexpertacademy.com/main/code/problem/problemDetail.do?contestProbId=AV15QRX6APsCFAYD&amp;amp;&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bI2PwZ/hyWrXzI9Sx/7tLkmLV3TgjEEYjkxFvt71/img.png?width=600&amp;amp;height=315&amp;amp;face=0_0_600_315');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;SW Expert Academy&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;SW 프로그래밍 역량 강화에 도움이 되는 다양한 학습 컨텐츠를 확인하세요!&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;swexpertacademy.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;pre id=&quot;code_1719988139255&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.*;

public class Solution {
    static class Coor {
        int x, y;
        public Coor (int x, int y) {
            this.x = x;
            this.y = y;
        }
    }
    static int dx[] = {-1, 1, 0, 0};
    static int dy[] = {0, 0, -1, 1};
    static int N, arr[][];
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        StringBuilder sb = new StringBuilder();
        int T = Integer.parseInt(br.readLine()); // 입력받는 데이터의 길이

        for (int t = 1; t &amp;lt;= T; t++) {
            N = Integer.parseInt(br.readLine());
            arr = new int[N][N];

            for (int i = 0; i &amp;lt; N; i++) {
                String s = br.readLine(); // 정보
                for (int j = 0; j &amp;lt; N; j++) {
                    arr[i][j] = s.charAt(j) - '0';
                }
            }

            sb.append(&quot;#&quot; + t + &quot; &quot; + bfs() + &quot;\n&quot;);
        }

        System.out.print(sb);
    }

    private static int bfs() {
        int tempArr[][] = new int[N][N];
        for (int i = 0; i &amp;lt; N; i++) Arrays.fill(tempArr[i], Integer.MAX_VALUE);
        Queue&amp;lt;Coor&amp;gt; q = new ArrayDeque&amp;lt;&amp;gt;();
        q.offer(new Coor(0, 0));
        tempArr[0][0] = 0;

        while(!q.isEmpty()) {
            Coor coor = q.poll();
            int x = coor.x;
            int y = coor.y;

            for (int d = 0; d &amp;lt; 4; d++) {
                int nx = x + dx[d];
                int ny = y + dy[d];
                if (nx &amp;lt; 0 || ny &amp;lt; 0 || nx &amp;gt;= N || ny &amp;gt;= N) continue;
                if (tempArr[x][y] + arr[nx][ny] &amp;lt; tempArr[nx][ny]) {
                    tempArr[nx][ny] = tempArr[x][y] + arr[nx][ny];
                    q.offer(new Coor(nx, ny));
                    }
                }
            }
        return tempArr[N-1][N-1];
    }
}
// 파손된 도로들은 이동 불가
// 출발지 S(0, 0) 에서 도착지 G(N-1, N-1)까지 가는 경로 중 복구 시간이 가장 짧은 경로에 대한 총 복구 시간 ㄱ하기
// 파여진 만큼의 복구 시간
// 최단거리 구하기 X 최단시간 구하기 O&lt;/code&gt;&lt;/pre&gt;</description>
      <category>SW Expert Academy</category>
      <author>c0mmedes</author>
      <guid isPermaLink="true">https://c0mmedes.tistory.com/168</guid>
      <comments>https://c0mmedes.tistory.com/168#entry168comment</comments>
      <pubDate>Wed, 3 Jul 2024 15:29:48 +0900</pubDate>
    </item>
    <item>
      <title>[프로그래머스] [JAVA] [Level 2] [완전탐색] 피로도</title>
      <link>https://c0mmedes.tistory.com/167</link>
      <description>&lt;figure id=&quot;og_1719466778705&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;프로그래머스&quot; data-og-description=&quot;코드 중심의 개발자 채용. 스택 기반의 포지션 매칭. 프로그래머스의 개발자 맞춤형 프로필을 등록하고, 나와 기술 궁합이 잘 맞는 기업들을 매칭 받으세요.&quot; data-og-host=&quot;programmers.co.kr&quot; data-og-source-url=&quot;https://school.programmers.co.kr/learn/courses/30/lessons/87946#&quot; data-og-url=&quot;https://programmers.co.kr/&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/baniIM/hyWrW7mzYi/jSV1N5tXjCe4QNJJVgQrXK/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630,https://scrap.kakaocdn.net/dn/bJMgy4/hyWrRZiPvS/0uJmIliWPJ841FJsinflCK/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630&quot;&gt;&lt;a href=&quot;https://school.programmers.co.kr/learn/courses/30/lessons/87946#&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://school.programmers.co.kr/learn/courses/30/lessons/87946#&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/baniIM/hyWrW7mzYi/jSV1N5tXjCe4QNJJVgQrXK/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630,https://scrap.kakaocdn.net/dn/bJMgy4/hyWrRZiPvS/0uJmIliWPJ841FJsinflCK/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;프로그래머스&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;코드 중심의 개발자 채용. 스택 기반의 포지션 매칭. 프로그래머스의 개발자 맞춤형 프로필을 등록하고, 나와 기술 궁합이 잘 맞는 기업들을 매칭 받으세요.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;programmers.co.kr&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1719466503154&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import java.util.*;
import java.io.*;

class Solution {
    static int numbers[];
    static boolean visited[];
    static int N, answer, mine;
    public int solution(int k, int[][] dungeons) {
        answer = -1;
        N = dungeons.length;
        mine = k;
        
        // 최대 개수 -&amp;gt; 순열로 던전의 수만큼 뽑기시작하고 그 값이 0이상일 때 break;
        // 최대의 경우의 수부터 뽑았기 때문
        for (int i = N; i &amp;gt; 0; i--) {
            numbers = new int[i];
            visited = new boolean[N];
            perm(i, 0, dungeons);
            if(answer &amp;gt; 0) break;
        }
        
        return answer;
    }
    private static void perm(int size, int cnt, int[][] dungeons) {
        if(cnt == size) {
            int temp = mine;
            int count = 0;
            for (int i = 0; i &amp;lt; numbers.length; i++){
                int index = numbers[i];
                int min = dungeons[index][0];// 최소 필요 피로도
                int use = dungeons[index][1];// 소모 피로도 
                if (temp &amp;lt; min) return;
                else {
                    temp -= use;
                    count++;
                }
            }
            answer = Math.max(count, answer);
            return;
        }
        
        for(int i = 0; i &amp;lt; N; i++) {
            if(visited[i]) continue;
            visited[i] = true;
            numbers[cnt] = i;
            perm(size, cnt + 1, dungeons);
            visited[i] = false;
        }
    }
}

// 각 던전마다 탐험 시작 최소 필요 피로도와 던전 탐험 후 소모 피로도가 있다.
// k - 현재 피로도, dungeons - 최소필요피로도, 소모피로도가 담긴 2차원 배열 던전
// 유저가 탐험할 수 있는 최대 던전 수 return&lt;/code&gt;&lt;/pre&gt;</description>
      <category>PROGRAMMERS/완전탐색</category>
      <category>java</category>
      <category>programmers</category>
      <author>c0mmedes</author>
      <guid isPermaLink="true">https://c0mmedes.tistory.com/167</guid>
      <comments>https://c0mmedes.tistory.com/167#entry167comment</comments>
      <pubDate>Thu, 27 Jun 2024 14:41:26 +0900</pubDate>
    </item>
    <item>
      <title>[BOJ] [JAVA] [GOLD 4] 17060 : 파이프 옮기기 2</title>
      <link>https://c0mmedes.tistory.com/166</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.acmicpc.net/problem/17069&quot;&gt;https://www.acmicpc.net/problem/17069&lt;/a&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1719293967144&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.StringTokenizer;

public class Main {
    static int N, arr[][];
    static long dp[][][];
    public static void main(String[] args) throws Exception{
        BufferedReader br =  new BufferedReader(new InputStreamReader(System.in));
        StringTokenizer st = new StringTokenizer(br.readLine());

        N = Integer.parseInt(st.nextToken());

        arr = new int[N][N];
        dp = new long[N][N][3]; // 방향까지 저장해줄 3차원배열

        for (int i = 0; i &amp;lt; N; i++) {
            st = new StringTokenizer(br.readLine());
            for (int j = 0; j &amp;lt; N; j++) {
                arr[i][j] = Integer.parseInt(st.nextToken());
            }
        }

        if (arr[N-1][N-1] == 1) {
            System.out.println(0);
            return;
        }

        // 시작점
        dp[0][1][0] = 1;

        for (int i = 0; i &amp;lt; N; i++) {
            // 아래, 오른쪽, 대각선으로만 이동하기 때문에 시작의 꼬리 다음칸인 2부터 시작
            for (int j = 2; j &amp;lt; N; j++) {
                if(arr[i][j] == 1) continue;

                // 가로 - 전의 칸에 가로와 대각선으로 도착한 애들 추가
                dp[i][j][0] = dp[i][j-1][0] + dp[i][j-1][2];

                // 세로일 경우 맨 위칸은 위랑 대각선에서 못옴
                if (i == 0) continue;
                dp[i][j][1] = dp[i-1][j][1] + dp[i-1][j][2];

                // 대각선일 경우 다음칸의 상 좌에 1이 있을 경우 이동못함
                if (arr[i-1][j] == 1 || arr[i][j-1] == 1) continue;
                dp[i][j][2] = dp[i-1][j-1][0] + dp[i-1][j-1][1] + dp[i-1][j-1][2];
            }
        }

        System.out.println(dp[N-1][N-1][0] + dp[N-1][N-1][1] + dp[N-1][N-1][2]);
    }
}

// 파이프는 연속된 2칸 차지
// 상하 좌우 좌상우하(대각선) 가능
// 1.1 - 1.2의 파이프를 N,N까지 이동시키는 경우의 수 구하기.&lt;/code&gt;&lt;/pre&gt;</description>
      <category>BAEKJOON/동적 계획법(Dynamic Programming)</category>
      <category>Baekjoon</category>
      <category>BOJ</category>
      <category>dp</category>
      <category>Dynamic Programming</category>
      <category>java</category>
      <category>동적 계획법</category>
      <author>c0mmedes</author>
      <guid isPermaLink="true">https://c0mmedes.tistory.com/166</guid>
      <comments>https://c0mmedes.tistory.com/166#entry166comment</comments>
      <pubDate>Tue, 25 Jun 2024 14:41:04 +0900</pubDate>
    </item>
    <item>
      <title>application.properties yaml git ignore 민감정보 숨기기</title>
      <link>https://c0mmedes.tistory.com/165</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;application-secret.properties&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;application-secret.yaml&lt;/p&gt;
&lt;pre id=&quot;code_1694483206737&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# application-secret.yml

spring:
  datasource:
    url: jdbc:mysql://localhost:3306/secretdb
    username: secretuser
    password: secretpassword

# 다른 시크릿 프로파일 관련 설정을 추가&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;application.yaml&lt;/p&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;spring:
  profiles:
    include: secret
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;application.properties&lt;/p&gt;
&lt;pre class=&quot;ini&quot;&gt;&lt;code&gt;spring.profiles.include=secret
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;git ignore에 application-secret.properties,&amp;nbsp;application-secret.yaml 등록&lt;/p&gt;</description>
      <category>SpringBoot</category>
      <category>ignore</category>
      <category>민감정보</category>
      <category>부트</category>
      <category>스프링</category>
      <category>스프링부트</category>
      <author>c0mmedes</author>
      <guid isPermaLink="true">https://c0mmedes.tistory.com/165</guid>
      <comments>https://c0mmedes.tistory.com/165#entry165comment</comments>
      <pubDate>Tue, 12 Sep 2023 10:48:01 +0900</pubDate>
    </item>
    <item>
      <title>[자바 ORM 표준 JPA 프로그래밍] [섹션 6] 다양한 연관관계 매핑</title>
      <link>https://c0mmedes.tistory.com/164</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;1. 연관관계 매핑시 고려사항 3가지&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;다중성
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;다대일: @ManyToOne&lt;/li&gt;
&lt;li&gt;일대다: @OneToMany&lt;/li&gt;
&lt;li&gt;일대일: @OneToOne&lt;/li&gt;
&lt;li&gt;다대다: @ManyToMany&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;단방향, 양방향
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;테이블
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;외래 키 하나로 양쪽 조인 가능&lt;/li&gt;
&lt;li&gt;사실 방향이라는 개념이 없음&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;객체
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;참조용 필드가 있는 쪽으로만 참조 가능&lt;/li&gt;
&lt;li&gt;한쪽만 참조하면 단방향&lt;/li&gt;
&lt;li&gt;양쪽이 서로 참조하면 양방향&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;연관관계의 주인
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;테이블은 외래 키 하나로 두 테이블이 연관관계를 맺음&lt;/li&gt;
&lt;li&gt;객체 양방향 관계는 A-&amp;gt;B, B-&amp;gt;A 처럼 참조가 2군데&lt;/li&gt;
&lt;li&gt;객체 양방향 관계는 참조가 2군데 있음. 둘중 테이블의 외래 키 를 관리할 곳을 지정해야함&lt;/li&gt;
&lt;li&gt;연관관계의 주인: 외래 키를 관리하는 참조&lt;/li&gt;
&lt;li&gt;주인의 반대편: 외래 키에 영향을 주지 않음, 단순 조회만 가능&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다대다는 실무에서 쓰면 안된다고 생각해라.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;객체 -&amp;gt; 양방향이라는건 사실 없다. (참조 입장에서 보면 단방향이 두개가 있어서 양쪽으로 걸기때문에 양방향처럼 보이는거임)&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;2. 다대일 [N:1]&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;가장많이 사용&lt;/li&gt;
&lt;li&gt;다대일의 반대는 일대다&lt;/li&gt;
&lt;li&gt;N쪽에 외래키가 항상 가야됨&lt;/li&gt;
&lt;li&gt;N이 연관관계의 주인&lt;/li&gt;
&lt;li&gt;양쪽을 서로 참조하도록 개발&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/sGJ7T/btsnEL7XNF1/Q5HmRv2r3yy9Rnmu12j4Mk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/sGJ7T/btsnEL7XNF1/Q5HmRv2r3yy9Rnmu12j4Mk/img.png&quot; data-origin-width=&quot;716&quot; data-origin-height=&quot;367&quot; data-is-animation=&quot;false&quot; style=&quot;width: 48.25%; margin-right: 10px;&quot; data-widthpercent=&quot;48.82&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/sGJ7T/btsnEL7XNF1/Q5HmRv2r3yy9Rnmu12j4Mk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FsGJ7T%2FbtsnEL7XNF1%2FQ5HmRv2r3yy9Rnmu12j4Mk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;716&quot; height=&quot;367&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bHxECb/btsnD2vAS1h/RaPBJPzIL5MyK8LDv03PR0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bHxECb/btsnD2vAS1h/RaPBJPzIL5MyK8LDv03PR0/img.png&quot; data-origin-width=&quot;720&quot; data-origin-height=&quot;352&quot; data-is-animation=&quot;false&quot; style=&quot;width: 50.5872%;&quot; data-widthpercent=&quot;51.18&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bHxECb/btsnD2vAS1h/RaPBJPzIL5MyK8LDv03PR0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbHxECb%2FbtsnD2vAS1h%2FRaPBJPzIL5MyK8LDv03PR0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;720&quot; height=&quot;352&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;3. 일대다 [1:N]&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;일대다 단방향&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;726&quot; data-origin-height=&quot;375&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/4QjnE/btsnD6Sh8Yd/TxTLArZMvCaYo4DDNIkpb0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/4QjnE/btsnD6Sh8Yd/TxTLArZMvCaYo4DDNIkpb0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/4QjnE/btsnD6Sh8Yd/TxTLArZMvCaYo4DDNIkpb0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F4QjnE%2FbtsnD6Sh8Yd%2FTxTLArZMvCaYo4DDNIkpb0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;726&quot; height=&quot;375&quot; data-origin-width=&quot;726&quot; data-origin-height=&quot;375&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;일대다 단방향 정리&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;일대다 단방향은 일대다(1:N)에서 일(1)이 연관관계의 주인&lt;/li&gt;
&lt;li&gt;테이블 일대다 관계는 항상 다(N) 쪽에 외래 키가 있음&lt;/li&gt;
&lt;li&gt;객체와 테이블의 차이 때문에 반대편 테이블의 외래 키를 관리하 는 특이한 구조&lt;/li&gt;
&lt;li&gt;@JoinColumn을 꼭 사용해야 함. 그렇지 않으면 조인 테이블 방식을 사용함(중간에 테이블을 하나 추가함)&lt;/li&gt;
&lt;li&gt;일대다 단방향 매핑의 단점
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;엔티티가 관리하는 외래 키가 다른 테이블에 있음&lt;/li&gt;
&lt;li&gt;연관관계 관리를 위해 추가로 UPDATE SQL 실행&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;일대다 단방향 매핑보다는 다대일 양방향 매핑을 사용하자&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1689439553417&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;package hellojpa;

import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.EntityTransaction;
import javax.persistence.Persistence;
import java.util.List;

public class JpaMain {
    public static void main(String[] args) {
        // Persistence.xml에서 설정해준 name으로 factory를 만들어서 연결
        // 웹 서버가 올라오는 시점에 딱 1개만 생성
        EntityManagerFactory emf = Persistence.createEntityManagerFactory(&quot;hello&quot;);

        // 고객의 요청이 올 때마다 썼다가 버림(em.close)
        // 그래서 쓰레드간에 절대 공유 X(사용하고 버려야됨)
        EntityManager em = emf.createEntityManager();

        EntityTransaction tx = em.getTransaction();

        tx.begin();

        // JPA의 모든 DATA 변경은 트랜잭션 안에서 실행
        // 단순 조회는 트랜잭션 필요 X
        try {
            Member member = new Member();
            member.setUsername(&quot;member1&quot;);

            em.persist(member);

            // Team Insert
            Team team = new Team();
            team.setName(&quot;TeamA&quot;);

            // 권장하지않음
            // 다대일 양방향 매핑 권장
            team.getMembers().add(member);

            em.persist(team);

            tx.commit();
        } catch (Exception e) {
            tx.rollback();
        } finally {
            em.close();
        }

        emf.close();
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1689439530216&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;package hellojpa;

import javax.persistence.*;

@Entity
public class Member {

    @Id @GeneratedValue
    @Column(name = &quot;MEMBER_ID&quot;)
    private Long id;

    @Column(name = &quot;USERNAME&quot;)
    private String username;

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }


}&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1689439507337&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;package hellojpa;

import javax.persistence.*;
import java.util.ArrayList;
import java.util.List;

@Entity
public class Team {
    @Id
    @GeneratedValue
    private Long id;
    private String name;

    @OneToMany
    @JoinColumn(name = &quot;TEAM_ID&quot;)
    private List&amp;lt;Member&amp;gt; members= new ArrayList&amp;lt;&amp;gt;();

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public List&amp;lt;Member&amp;gt; getMembers() {
        return members;
    }

    public void setMembers(List&amp;lt;Member&amp;gt; members) {
        this.members = members;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;일대다 단방향&lt;/b&gt;&lt;b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;720&quot; data-origin-height=&quot;373&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/uaITO/btsnIKUgat8/7ftQpWvQDUeCYLkdLFBnm1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/uaITO/btsnIKUgat8/7ftQpWvQDUeCYLkdLFBnm1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/uaITO/btsnIKUgat8/7ftQpWvQDUeCYLkdLFBnm1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FuaITO%2FbtsnIKUgat8%2F7ftQpWvQDUeCYLkdLFBnm1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;720&quot; height=&quot;373&quot; data-origin-width=&quot;720&quot; data-origin-height=&quot;373&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;일대다 양방향 정리&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;이런 매핑은 공식적으로 존재X&lt;/li&gt;
&lt;li&gt;@JoinColumn(insertable=false, updatable=false)&lt;/li&gt;
&lt;li&gt;읽기 전용 필드를 사용해서 양방향 처럼 사용하는 방법&lt;/li&gt;
&lt;li&gt;다대일 양방향을 사용하자&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;결론 - 일대다보다는 다대일 양방향 매핑을 쓰자.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;4. 일대일 [1:1]&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;일대일 관계&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;일대일 관계는 그 반대도 일대일&lt;/li&gt;
&lt;li&gt;주 테이블이나 대상 테이블 중에 외래 키 선택 가능
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;주 테이블에 외래 키&lt;/li&gt;
&lt;li&gt;대상 테이블에 외래 키&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;외래 키에 데이터베이스 유니크(UNI) 제약조건 추가&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;722&quot; data-origin-height=&quot;365&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/EqiGD/btsnOtdyd2c/97qAqFXSBvCNvvvzMyHApk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/EqiGD/btsnOtdyd2c/97qAqFXSBvCNvvvzMyHApk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/EqiGD/btsnOtdyd2c/97qAqFXSBvCNvvvzMyHApk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FEqiGD%2FbtsnOtdyd2c%2F97qAqFXSBvCNvvvzMyHApk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;722&quot; height=&quot;365&quot; data-origin-width=&quot;722&quot; data-origin-height=&quot;365&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;다대일(@ManyToOne) 단방향 매핑과 유사&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;720&quot; data-origin-height=&quot;353&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cmiifd/btsnFEm9lMv/9UDakZbGgRVnEoQxQOFpy1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cmiifd/btsnFEm9lMv/9UDakZbGgRVnEoQxQOFpy1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cmiifd/btsnFEm9lMv/9UDakZbGgRVnEoQxQOFpy1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fcmiifd%2FbtsnFEm9lMv%2F9UDakZbGgRVnEoQxQOFpy1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;720&quot; height=&quot;353&quot; data-origin-width=&quot;720&quot; data-origin-height=&quot;353&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;다대일 양방향 매핑 처럼 외래 키가 있는 곳이 연관관계의 주인&lt;/li&gt;
&lt;li&gt;반대편은 mappedBy 적용&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;720&quot; data-origin-height=&quot;356&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/boTrw3/btsnEnNehnv/fJPjFiuH16DrMsqHzLxovk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/boTrw3/btsnEnNehnv/fJPjFiuH16DrMsqHzLxovk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/boTrw3/btsnEnNehnv/fJPjFiuH16DrMsqHzLxovk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FboTrw3%2FbtsnEnNehnv%2FfJPjFiuH16DrMsqHzLxovk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;720&quot; height=&quot;356&quot; data-origin-width=&quot;720&quot; data-origin-height=&quot;356&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;단방향 관계는 JPA 지원X&lt;/li&gt;
&lt;li&gt;양방향 관계는 지원&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;720&quot; data-origin-height=&quot;362&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/veiSX/btsnGZEjRB2/sSzNmfHGmdV35KNfL1wO9k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/veiSX/btsnGZEjRB2/sSzNmfHGmdV35KNfL1wO9k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/veiSX/btsnGZEjRB2/sSzNmfHGmdV35KNfL1wO9k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FveiSX%2FbtsnGZEjRB2%2FsSzNmfHGmdV35KNfL1wO9k%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;720&quot; height=&quot;362&quot; data-origin-width=&quot;720&quot; data-origin-height=&quot;362&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;사실 일대일 주 테이블에 외래 키 양방향과 매핑 방법은 같음&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;일대일 정리&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;주 테이블에 외래 키
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;주 객체가 대상 객체의 참조를 가지는 것 처럼 주 테이블에 외래 키를 두고 대상 테이블을 찾음&lt;/li&gt;
&lt;li&gt;객체지향 개발자 선호&lt;/li&gt;
&lt;li&gt;JPA 매핑 편리&lt;/li&gt;
&lt;li&gt;장점: 주 테이블만 조회해도 대상 테이블에 데이터가 있는지 확인 가능&lt;/li&gt;
&lt;li&gt;단점: 값이 없으면 외래 키에 null 허용&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;대상 테이블에 외래 키
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;대상 테이블에 외래 키가 존재&lt;/li&gt;
&lt;li&gt;전통적인 데이터베이스 개발자 선호&lt;/li&gt;
&lt;li&gt;장점: 주 테이블과 대상 테이블을 일대일에서 일대다 관계로 변경할 때 테이블 구조 유지&lt;/li&gt;
&lt;li&gt;단점: 프록시 기능의 한계로 지연 로딩으로 설정해도 항상 즉시 로딩됨(프록시는 뒤에서 설명)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1689496743361&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;//public class Member 

@OneToOne
    @JoinColumn(name = &quot;LOCKER_ID&quot;)
    private Locker locker;

// ------------------ //

public class Locker {

    @Id @GeneratedValue
    private Long id;
    private String name;


    // 양방향
//    @OneToOne(mappedBy = &quot;locker&quot;)
//    private Member member;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;5. 다대다 [N:M]&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;실무에서 쓰면 안된다. (왜 안되는지 알자)&lt;/li&gt;
&lt;li&gt;관계형 데이터베이스는 정규화된 테이블 2개로 다대다 관계를 표현할 수 없음&lt;/li&gt;
&lt;li&gt;연결 테이블을 추가해서 일대다, 다대일 관계로 풀어내야함&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;382&quot; data-origin-height=&quot;148&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cZBLYT/btsnEkwe8kY/Jo057yesD5m97nQ3Sd2u7K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cZBLYT/btsnEkwe8kY/Jo057yesD5m97nQ3Sd2u7K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cZBLYT/btsnEkwe8kY/Jo057yesD5m97nQ3Sd2u7K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcZBLYT%2FbtsnEkwe8kY%2FJo057yesD5m97nQ3Sd2u7K%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;382&quot; height=&quot;148&quot; data-origin-width=&quot;382&quot; data-origin-height=&quot;148&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;객체는 컬렉션을 사용해서 객체 2개로 다대다 관계 가능&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;460&quot; data-origin-height=&quot;208&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bceQ0C/btsnOrNCokI/e9zuKla6CgnEHHmJhGtTF0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bceQ0C/btsnOrNCokI/e9zuKla6CgnEHHmJhGtTF0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bceQ0C/btsnOrNCokI/e9zuKla6CgnEHHmJhGtTF0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbceQ0C%2FbtsnOrNCokI%2Fe9zuKla6CgnEHHmJhGtTF0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;460&quot; height=&quot;208&quot; data-origin-width=&quot;460&quot; data-origin-height=&quot;208&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;@ManyToMany 사용&lt;/li&gt;
&lt;li&gt;@JoinTable로 연결 테이블 지정&lt;/li&gt;
&lt;li&gt;다대다 매핑: 단방향, 양방향 가능&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;다대다 매핑의 한계&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;편리해 보이지만 실무에서 사용X&lt;/li&gt;
&lt;li&gt;연결 테이블이 단순히 연결만 하고 끝나지 않음&lt;/li&gt;
&lt;li&gt;주문시간, 수량 같은 데이터가 들어올 수 있음&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;530&quot; data-origin-height=&quot;94&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/4asaa/btsnFas8EHo/OUjUvn7337wEHcyxqiqNjk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/4asaa/btsnFas8EHo/OUjUvn7337wEHcyxqiqNjk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/4asaa/btsnFas8EHo/OUjUvn7337wEHcyxqiqNjk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F4asaa%2FbtsnFas8EHo%2FOUjUvn7337wEHcyxqiqNjk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;530&quot; height=&quot;94&quot; data-origin-width=&quot;530&quot; data-origin-height=&quot;94&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;다대다 한계 극복&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;연결 테이블용 엔티티 추가(연결 테이블을 엔티티로 승격&lt;/li&gt;
&lt;li&gt;@ManyToMany -&amp;gt; @OneToMany, @ManyToOne&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;473&quot; data-origin-height=&quot;181&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cVwgeK/btsnLciQudY/8D36k7lv0kYCMSHmUCSxS0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cVwgeK/btsnLciQudY/8D36k7lv0kYCMSHmUCSxS0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cVwgeK/btsnLciQudY/8D36k7lv0kYCMSHmUCSxS0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcVwgeK%2FbtsnLciQudY%2F8D36k7lv0kYCMSHmUCSxS0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;473&quot; height=&quot;181&quot; data-origin-width=&quot;473&quot; data-origin-height=&quot;181&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;pre id=&quot;code_1689498086208&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;package hellojpa;

import javax.persistence.*;
import java.time.LocalDateTime;

@Entity
public class MemberProduct {

    @Id @GeneratedValue
    private Long id;

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

    @ManyToOne
    @JoinColumn(name = &quot;PRODUCT_ID&quot;)
    private Product product;

    private int count;
    private int price;

    private LocalDateTime orderDateTime;

}&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1689498095631&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;package hellojpa;

import javax.persistence.*;
import java.util.ArrayList;
import java.util.List;

@Entity
public class Product {
    @Id @GeneratedValue
    private Long id;
    private String name;
    @OneToMany(mappedBy = &quot;prodcut&quot;)
    private List&amp;lt;MemberProduct&amp;gt; memberProducts = new ArrayList&amp;lt;&amp;gt;();

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public List&amp;lt;MemberProduct&amp;gt; getMemberProducts() {
        return memberProducts;
    }

    public void setMemberProducts(List&amp;lt;MemberProduct&amp;gt; memberProducts) {
        this.memberProducts = memberProducts;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1689498111023&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;package hellojpa;

import javax.persistence.*;
import java.util.ArrayList;
import java.util.List;

@Entity
public class Member {

    @Id @GeneratedValue
    @Column(name = &quot;MEMBER_ID&quot;)
    private Long id;

    @Column(name = &quot;USERNAME&quot;)
    private String username;

    @OneToOne
    @JoinColumn(name = &quot;LOCKER_ID&quot;)
    private Locker locker;

    @OneToMany(mappedBy = &quot;member&quot;)
    private List&amp;lt;MemberProduct&amp;gt; memberProductList = new ArrayList&amp;lt;&amp;gt;();

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }


}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;6. 실전 예제 - 다양한 연관관계 매핑&lt;/b&gt;&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;955&quot; data-origin-height=&quot;584&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/4WKbS/btsnFEVb87y/reWnKrtHkIF6AJHN6fmQqk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/4WKbS/btsnFEVb87y/reWnKrtHkIF6AJHN6fmQqk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/4WKbS/btsnFEVb87y/reWnKrtHkIF6AJHN6fmQqk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F4WKbS%2FbtsnFEVb87y%2FreWnKrtHkIF6AJHN6fmQqk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;955&quot; height=&quot;584&quot; data-origin-width=&quot;955&quot; data-origin-height=&quot;584&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;956&quot; data-origin-height=&quot;645&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bmZYDI/btsnLaS1eDW/qgEpu0VLUGj6BCCZP1tOnk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bmZYDI/btsnLaS1eDW/qgEpu0VLUGj6BCCZP1tOnk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bmZYDI/btsnLaS1eDW/qgEpu0VLUGj6BCCZP1tOnk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbmZYDI%2FbtsnLaS1eDW%2FqgEpu0VLUGj6BCCZP1tOnk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;956&quot; height=&quot;645&quot; data-origin-width=&quot;956&quot; data-origin-height=&quot;645&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;955&quot; data-origin-height=&quot;646&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/RJa6s/btsnF6jA9ry/WKEfMKTFZBcO0Kwg3EsEFk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/RJa6s/btsnF6jA9ry/WKEfMKTFZBcO0Kwg3EsEFk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/RJa6s/btsnF6jA9ry/WKEfMKTFZBcO0Kwg3EsEFk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FRJa6s%2FbtsnF6jA9ry%2FWKEfMKTFZBcO0Kwg3EsEFk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;955&quot; height=&quot;646&quot; data-origin-width=&quot;955&quot; data-origin-height=&quot;646&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;N:M 관계는 1:N, N:1로&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;테이블의 N:M 관계는 중간 테이블을 이용해서 1:N, N:1&lt;/li&gt;
&lt;li&gt;실전에서는 중간 테이블이 단순하지 않다.&lt;/li&gt;
&lt;li&gt;@ManyToMany는 제약: 필드 추가X, 엔티티 테이블 불일치&lt;/li&gt;
&lt;li&gt;실전에서는 @ManyToMany 사용X&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;@JoinColumn&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;외래 키를 매핑할 때 사용&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;954&quot; data-origin-height=&quot;423&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cdLlV2/btsnOtdMP8J/jjKbmMOk1TTZSZMDM5a6g0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cdLlV2/btsnOtdMP8J/jjKbmMOk1TTZSZMDM5a6g0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cdLlV2/btsnOtdMP8J/jjKbmMOk1TTZSZMDM5a6g0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcdLlV2%2FbtsnOtdMP8J%2FjjKbmMOk1TTZSZMDM5a6g0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;954&quot; height=&quot;423&quot; data-origin-width=&quot;954&quot; data-origin-height=&quot;423&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;@ManyToOne&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;950&quot; data-origin-height=&quot;481&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cnTWX6/btsnFEHF1PS/7wJqQDLk6KsZV8YdnZHMok/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cnTWX6/btsnFEHF1PS/7wJqQDLk6KsZV8YdnZHMok/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cnTWX6/btsnFEHF1PS/7wJqQDLk6KsZV8YdnZHMok/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcnTWX6%2FbtsnFEHF1PS%2F7wJqQDLk6KsZV8YdnZHMok%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;950&quot; height=&quot;481&quot; data-origin-width=&quot;950&quot; data-origin-height=&quot;481&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;@OneToMany&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;952&quot; data-origin-height=&quot;495&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cFe928/btsnEM7kRHM/IM6NCpJdnVVntdcK7cxtd0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cFe928/btsnEM7kRHM/IM6NCpJdnVVntdcK7cxtd0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cFe928/btsnEM7kRHM/IM6NCpJdnVVntdcK7cxtd0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcFe928%2FbtsnEM7kRHM%2FIM6NCpJdnVVntdcK7cxtd0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;952&quot; height=&quot;495&quot; data-origin-width=&quot;952&quot; data-origin-height=&quot;495&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;</description>
      <category>JPA/자바 ORM 표준 JPA 프로그래밍</category>
      <category>inflearn</category>
      <category>jpa</category>
      <category>ORM</category>
      <category>spring</category>
      <category>springboot</category>
      <category>김영한</category>
      <category>인프런</category>
      <author>c0mmedes</author>
      <guid isPermaLink="true">https://c0mmedes.tistory.com/164</guid>
      <comments>https://c0mmedes.tistory.com/164#entry164comment</comments>
      <pubDate>Mon, 17 Jul 2023 01:11:56 +0900</pubDate>
    </item>
    <item>
      <title>[자바 ORM 표준 JPA 프로그래밍] [섹션 5] 연관관계 매핑 기초</title>
      <link>https://c0mmedes.tistory.com/163</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;Z1. 단방향 연관관계&lt;/b&gt;&lt;b&gt;&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;객체를 테이블에 맞추어 데이터 중심으로 모델링하면, 협력 관계를 만들 수 없다.&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;테이블은 외래 키로 조인을 사용해서 연관된 테이블을 찾는다.&lt;/li&gt;
&lt;li&gt;객체는 참조를 사용해서 연관된 객체를 찾는다.&lt;/li&gt;
&lt;li&gt;테이블과 객체 사이에는 이런 큰 간격이 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;객체를 테이블에 맞추어 모델링 (연관관계가 없는 객체)&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;680&quot; data-origin-height=&quot;401&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/rYXLT/btsnDyml91c/HJj4XQK64ynJiJeiI0VAs0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/rYXLT/btsnDyml91c/HJj4XQK64ynJiJeiI0VAs0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/rYXLT/btsnDyml91c/HJj4XQK64ynJiJeiI0VAs0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FrYXLT%2FbtsnDyml91c%2FHJj4XQK64ynJiJeiI0VAs0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;680&quot; height=&quot;401&quot; data-origin-width=&quot;680&quot; data-origin-height=&quot;401&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;객체 지향 모델링 (ORM 매핑)&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;732&quot; data-origin-height=&quot;398&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/sow2B/btsnD3sCbg3/UAjWrKrCfaIgxLKTd8PKKk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/sow2B/btsnD3sCbg3/UAjWrKrCfaIgxLKTd8PKKk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/sow2B/btsnD3sCbg3/UAjWrKrCfaIgxLKTd8PKKk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fsow2B%2FbtsnD3sCbg3%2FUAjWrKrCfaIgxLKTd8PKKk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;732&quot; height=&quot;398&quot; data-origin-width=&quot;732&quot; data-origin-height=&quot;398&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Member.java&lt;/p&gt;
&lt;pre id=&quot;code_1689299625352&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;package hellojpa;

import javax.persistence.*;

@Entity
public class Member {

    @Id @GeneratedValue
    @Column(name = &quot;MEMBER_ID&quot;)
    private Long id;

    @Column(name = &quot;USERNAME&quot;)
    private String username;

    @ManyToOne // 다대일 (멤버 N : 팀 1)
    @JoinColumn(name = &quot;TEAM_ID&quot;) // 매핑해야되는 컬럼
    private Team team;

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public Team getTeam() {
        return team;
    }

    public void setTeam(Team team) {
        this.team = team;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Team.java&lt;/p&gt;
&lt;pre id=&quot;code_1689299635295&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;package hellojpa;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;

@Entity
public class Team {
    @Id
    @GeneratedValue
    private Long id;
    private String name;

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;JpaMain.java&lt;/p&gt;
&lt;pre id=&quot;code_1689299589692&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;package hellojpa;

import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.EntityTransaction;
import javax.persistence.Persistence;

public class JpaMain {
    public static void main(String[] args) {
        // Persistence.xml에서 설정해준 name으로 factory를 만들어서 연결
        // 웹 서버가 올라오는 시점에 딱 1개만 생성
        EntityManagerFactory emf = Persistence.createEntityManagerFactory(&quot;hello&quot;);

        // 고객의 요청이 올 때마다 썼다가 버림(em.close)
        // 그래서 쓰레드간에 절대 공유 X(사용하고 버려야됨)
        EntityManager em = emf.createEntityManager();

        EntityTransaction tx = em.getTransaction();

        tx.begin();

        // JPA의 모든 DATA 변경은 트랜잭션 안에서 실행
        // 단순 조회는 트랜잭션 필요 X
        try {
            // * insert
//            Member member = new Member();
//            member.setId(1L);
//            member.setName(&quot;HelloA&quot;);
//            em.persist(member);

            // * select
//            Member findMember = em.find(Member.class, 1L);
//            System.out.println(&quot;findMember.id = &quot; + findMember.getId());
//            System.out.println(&quot;findMember.name = &quot; + findMember.getId());

            // * delete
//            Member findMember = em.find(Member.class, 1L);
//            em.remove(findMember);

            // * update
            // 객체에서 값만 바꿔도 되는 이유는 JPA가 관리해서 트랜잭션을
            // 커밋하는 시점에 다 체크해서 UPDATE 쿼리를 만들어서 날림 그 이후에 커밋
//            Member findMember = em.find(Member.class, 1L);
//            findMember.setName(&quot;HelloJPA&quot;);

            // 저장
            Team team = new Team();
            team.setName(&quot;TeamA&quot;);
            em.persist(team);

            Member member = new Member();
            member.setUsername(&quot;member1&quot;);
            member.setTeam(team);
            em.persist(member);

            // 영속성 컨텍스트 말고 DB에서 가져오는걸 보고싶을 때
//            em.flush();
//            em.clear();

            Member findMember = em.find(Member.class, member.getId());
            Team findTeam = findMember.getTeam();
            System.out.println(&quot;findTeam = &quot; + findTeam.getName());

            tx.commit();
        } catch (Exception e) {
            tx.rollback();
        } finally {
            em.close();
        }

        emf.close();
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;2. 양방향 연관관계와 연관관계의 주인&amp;nbsp;&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;양방향 매핑&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;798&quot; data-origin-height=&quot;468&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bEFNex/btsnBSeTpb8/UKiLPVlqAKpwGSd3Yc6njK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bEFNex/btsnBSeTpb8/UKiLPVlqAKpwGSd3Yc6njK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bEFNex/btsnBSeTpb8/UKiLPVlqAKpwGSd3Yc6njK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbEFNex%2FbtsnBSeTpb8%2FUKiLPVlqAKpwGSd3Yc6njK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;798&quot; height=&quot;468&quot; data-origin-width=&quot;798&quot; data-origin-height=&quot;468&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;연관관계의 주인과 mappedBy&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;mappedBy = JPA의 멘탈붕괴 난이도&lt;/li&gt;
&lt;li&gt;mappedBy는 처음에는 이해하기 어렵다.&lt;/li&gt;
&lt;li&gt;객체와 테이블간에 연관관계를 맺는 차이를 이해해야 한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;객체와 테이블이 관계를 맺는 차이&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;객체 연관관계 = 2개
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;회원 -&amp;gt; 팀 연관관계 1개(단방향)&lt;/li&gt;
&lt;li&gt;팀 -&amp;gt; 회원 연관관계 1개(단방향)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;테이블 연관관계 = 1개
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;회원 &amp;lt;-&amp;gt; 팀의 연관관계 1개(양방향)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;객체의 양방향 관계&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;객체의 양방향 관계는 사실 양방향 관계가 아니라 서로 다른 단 뱡향 관계 2개다.&lt;/li&gt;
&lt;li&gt;객체를 양방향으로 참조하려면 단방향 연관관계를 2개 만들어야 한다.&lt;/li&gt;
&lt;li&gt;A -&amp;gt; B (a.getB())&lt;/li&gt;
&lt;li&gt;B -&amp;gt; A (b.getA())&lt;/li&gt;
&lt;li&gt;ex) class A { B b; }, class B { A a; }&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;테이블의 양방향 관계&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;테이블은 외래 키 하나로 두 테이블의 연관관계를 관리&lt;/li&gt;
&lt;li&gt;MEMBER.TEAM_ID 외래 키 하나로 양방향 연관관계 가짐 (양쪽으로 조인할 수 있다.)&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1689321567486&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT *
FROM MEMBER M
JOIN TEAM T ON M.TEAM_ID = T.TEAM_ID

SELECT *
FROM TEAM T
JOIN MEMBER M ON T.TEAM_ID = M.TEAM_ID&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;둘 중 하나로 외래 키를 관리해야 한다.&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;683&quot; data-origin-height=&quot;355&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cZC6UZ/btsnFFrpzWB/aKcLltOVyZgPqOKIPSBmf1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cZC6UZ/btsnFFrpzWB/aKcLltOVyZgPqOKIPSBmf1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cZC6UZ/btsnFFrpzWB/aKcLltOVyZgPqOKIPSBmf1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcZC6UZ%2FbtsnFFrpzWB%2FaKcLltOVyZgPqOKIPSBmf1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;683&quot; height=&quot;355&quot; data-origin-width=&quot;683&quot; data-origin-height=&quot;355&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;연관관계의 주인(Owner)&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;양방향 매핑 규칙&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;객체의 두 관계중 하나를 연관관계의 주인으로 지정&lt;/li&gt;
&lt;li&gt;연관관계의 주인만이 외래 키를 관리(등록, 수정)&lt;/li&gt;
&lt;li&gt;주인이 아닌쪽은 읽기만 가능&lt;/li&gt;
&lt;li&gt;주인은 mappedBy 속성 사용X&lt;/li&gt;
&lt;li&gt;주인이 아니면 mappedBy 속성으로 주인 지정&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;누구를 주인으로?&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;외래 키가 있는 있는 곳을 주인으로 정해라&lt;/li&gt;
&lt;li&gt;여기서는 Member.team이 연관관계의 주인&lt;/li&gt;
&lt;li&gt;N쪽이 연관관계의 주인&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;601&quot; data-origin-height=&quot;320&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/qjU5m/btsnD1CiiwA/nwyqDUiB2gl7uquqBPFJSK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/qjU5m/btsnD1CiiwA/nwyqDUiB2gl7uquqBPFJSK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/qjU5m/btsnD1CiiwA/nwyqDUiB2gl7uquqBPFJSK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FqjU5m%2FbtsnD1CiiwA%2FnwyqDUiB2gl7uquqBPFJSK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;601&quot; height=&quot;320&quot; data-origin-width=&quot;601&quot; data-origin-height=&quot;320&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;3. 양방향 연관관계와 연관관계의 주인 2 - 주의점, 정리&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;양방향 매핑시 가장 많이 하는 실수 (연관관계의 주인에 값을 입력하지 않음)&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1689343265782&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Team team = new Team();
 team.setName(&quot;TeamA&quot;);
 em.persist(team);
 Member member = new Member();
 member.setName(&quot;member1&quot;);
 //역방향(주인이 아닌 방향)만 연관관계 설정
 team.getMembers().add(member);
 em.persist(member);&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;333&quot; data-origin-height=&quot;65&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/59nsw/btsnD5ZDlPU/K47tnVPIjbp5Oz8idG5k61/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/59nsw/btsnD5ZDlPU/K47tnVPIjbp5Oz8idG5k61/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/59nsw/btsnD5ZDlPU/K47tnVPIjbp5Oz8idG5k61/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F59nsw%2FbtsnD5ZDlPU%2FK47tnVPIjbp5Oz8idG5k61%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;333&quot; height=&quot;65&quot; data-origin-width=&quot;333&quot; data-origin-height=&quot;65&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;양방향 매핑시 연관관계의 주인에 값을 입력해야 한다. (순수한 객체 관계를 고려하면 항상 양쪽다 값을 입력해야 한다.)&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1689343316686&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Team team = new Team();
 team.setName(&quot;TeamA&quot;);
 em.persist(team);
 Member member = new Member();
 member.setName(&quot;member1&quot;);
 team.getMembers().add(member);
 //연관관계의 주인에 값 설정
 member.setTeam(team); //**
 em.persist(member);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;양방향 연관관계 주의 - 실습&lt;/b&gt;&lt;b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;순수 객체 상태를 고려해서 항상 양쪽에 값을 설정하자&lt;/li&gt;
&lt;li&gt;연관관계 편의 메소드를 생성하자&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1689351634120&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt; /* jpaMain.java */
 Team team = new Team();
            team.setName(&quot;TeamA&quot;);
            em.persist(team);

            Member member = new Member();
            member.setUsername(&quot;member1&quot;);

//            setTeam에서 해주도록 등록해놨기 때문에 필요없음
//            team.getMembers().add(member);

            //연관관계의 주인에 값 설정
            member.setTeam(team); //**
            em.persist(member);


public void setTeam(Team team) {
        this.team = team;
        // this == member
        team.getMembers().add(this);
}&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;양방향 매핑시에 무한 루프를 조심하자
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;예: toString(), lombok, JSON 생성 라이브러리&lt;/li&gt;
&lt;li&gt;lombok에서 tostring 만드는건 웬만하면 쓰지말자&lt;/li&gt;
&lt;li&gt;컨트롤러에서 엔티티를 바로 반환x (컨트롤러에서 dto로 변환해서 반환해라)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;양방향 매핑 정리&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;단방향 매핑만으로도 이미 연관관계 매핑은 완료 (처음 설계할 때는 무조건 단방향으로 해라)&lt;/li&gt;
&lt;li&gt;양방향 매핑은 반대 방향으로 조회(객체 그래프 탐색) 기능이 추가된 것 뿐&lt;/li&gt;
&lt;li&gt;JPQL에서 역방향으로 탐색할 일이 많음&lt;/li&gt;
&lt;li&gt;단방향 매핑을 잘 하고 양방향은 필요할 때 추가해도 됨 (테이블에 영향을 주지 않음)&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;연관관계의 주인을 정하는 기준&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;비즈니스 로직을 기준으로 연관관계의 주인을 선택하면 안됨&lt;/li&gt;
&lt;li&gt;연관관계의 주인은 외래 키의 위치를 기준으로 정해야함&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;4. 실전 예제 - 2. 연관관계 매핑 시작&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;실전 예제 1에서 했던 프로젝트를 연관관계로 바꾸자&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/IFid0/btsnD1XDEeM/KOYK9kKCbUaDrPLxtgk910/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/IFid0/btsnD1XDEeM/KOYK9kKCbUaDrPLxtgk910/img.png&quot; data-origin-width=&quot;533&quot; data-origin-height=&quot;370&quot; data-is-animation=&quot;false&quot; data-widthpercent=&quot;48.16&quot; style=&quot;width: 47.6008%; margin-right: 10px;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/IFid0/btsnD1XDEeM/KOYK9kKCbUaDrPLxtgk910/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FIFid0%2FbtsnD1XDEeM%2FKOYK9kKCbUaDrPLxtgk910%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;533&quot; height=&quot;370&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/NQszc/btsnLbjAWSm/aIpKgzmh8yqJRVpAf8kvAK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/NQszc/btsnLbjAWSm/aIpKgzmh8yqJRVpAf8kvAK/img.png&quot; data-origin-width=&quot;552&quot; data-origin-height=&quot;356&quot; data-is-animation=&quot;false&quot; style=&quot;width: 51.2364%;&quot; data-widthpercent=&quot;51.84&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/NQszc/btsnLbjAWSm/aIpKgzmh8yqJRVpAf8kvAK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FNQszc%2FbtsnLbjAWSm%2FaIpKgzmh8yqJRVpAf8kvAK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;552&quot; height=&quot;356&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Member.java&lt;/p&gt;
&lt;pre id=&quot;code_1689405803334&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;package jpabook.jpashop.domain;

import javax.persistence.*;
import java.util.ArrayList;
import java.util.List;

@Entity
public class Member {

    // @GeneratedValue의 Default는 Auto
    @Id @GeneratedValue
    @Column(name = &quot;MEMBER_ID&quot;)
    private Long id;
    private String name;
    private String city;
    private String street;
    private String zipcode;

    // Order의 member가 연관관계의 주인
    @OneToMany(mappedBy = &quot;member&quot;)
    private List&amp;lt;Order&amp;gt; orders = new ArrayList&amp;lt;&amp;gt;();

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getCity() {
        return city;
    }

    public void setCity(String city) {
        this.city = city;
    }

    public String getStreet() {
        return street;
    }

    public void setStreet(String street) {
        this.street = street;
    }

    public String getZipcode() {
        return zipcode;
    }

    public void setZipcode(String zipcode) {
        this.zipcode = zipcode;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Order.java&lt;/p&gt;
&lt;pre id=&quot;code_1689405814222&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;package jpabook.jpashop.domain;

import javax.persistence.*;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;

@Entity
@Table(name = &quot;ORDERS&quot;) // db의 예약어가 order인 경우가 있어서
public class Order {

    @Id @GeneratedValue
    @Column(name = &quot;ORDER_ID&quot;)
    private Long id;

    // 주문자명
    // 관계형DB를 객체에 만든 설계
//    @Column(name = &quot;MEMBER_ID&quot;)
//    private Long memberId;

    // 연관관계 매핑
    @ManyToOne
    @JoinColumn(name = &quot;MEMBER_ID&quot;)
    private Member member;

    @OneToMany(mappedBy = &quot;order&quot;)
    private List&amp;lt;OrderItem&amp;gt; orderItems = new ArrayList&amp;lt;&amp;gt;();

    // 연관관계 편의 메서드
    public void addOrderItem(OrderItem orderItem) {
        orderItems.add(orderItem);
        orderItem.setOrder(this);
    }

    public Member getMember() {
        return member;
    }

    public void setMember(Member member) {
        this.member = member;
    }

    // 이게 객체지향적인 코드
//    Private Member member
//    public Private getMember() {
//        return Member;
//    }

    private LocalDateTime orderDate;

    @Enumerated(EnumType.STRING)
    private OrderStatus status;



    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

//    public Long getMemberId() {
//        return memberId;
//    }
//
//    public void setMemberId(Long memberId) {
//        this.memberId = memberId;
//    }

    public LocalDateTime getOrderDate() {
        return orderDate;
    }

    public void setOrderDate(LocalDateTime orderDate) {
        this.orderDate = orderDate;
    }

    public OrderStatus getStatus() {
        return status;
    }

    public void setStatus(OrderStatus status) {
        this.status = status;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Item.java&lt;/p&gt;
&lt;pre id=&quot;code_1689405834503&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;package jpabook.jpashop.domain;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;

@Entity
public class Item {

    @Id @GeneratedValue
    @Column(name = &quot;ITEM_ID&quot;)
    private Long id;
    private String name;
    private int price;
    private int stockQuantity;

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getPrice() {
        return price;
    }

    public void setPrice(int price) {
        this.price = price;
    }

    public int getStockQuantity() {
        return stockQuantity;
    }

    public void setStockQuantity(int stockQuantity) {
        this.stockQuantity = stockQuantity;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;OrderItem.java&lt;/p&gt;
&lt;pre id=&quot;code_1689405851718&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;package jpabook.jpashop.domain;

import javax.persistence.*;

@Entity
public class OrderItem {

    @Id @GeneratedValue
    @Column(name = &quot;ORDER_ITEM_ID&quot;)
    private Long id;
//    @Column(name = &quot;ORDER_ID&quot;)
//    private Long orderId;

//    @Column(name = &quot;ITEM_ID&quot;)
//    private Long itemid;
    @ManyToOne
    @Column(name = &quot;ORDER_ID&quot;)
    private Order order;

    @ManyToOne
    @Column(name = &quot;ITEM_ID&quot;)
    private Item Item;

    private Long orderPrice;
    private int count;

    public Long getId() {
        return id;
    }

    public Order getOrder() {
        return order;
    }

    public void setOrder(Order order) {
        this.order = order;
    }

    public void setId(Long id) {
        this.id = id;
    }

//    public Long getOrderId() {
//        return orderId;
//    }
//
//    public void setOrderId(Long orderId) {
//        this.orderId = orderId;
//    }
//
//    public Long getItemid() {
//        return itemid;
//    }
//
//    public void setItemid(Long itemid) {
//        this.itemid = itemid;
//    }

    public Long getOrderPrice() {
        return orderPrice;
    }

    public void setOrderPrice(Long orderPrice) {
        this.orderPrice = orderPrice;
    }

    public int getCount() {
        return count;
    }

    public void setCount(int count) {
        this.count = count;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;JpaMain.java&lt;/p&gt;
&lt;pre id=&quot;code_1689405908431&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;package jpabook.jpashop;

import jpabook.jpashop.domain.Order;
import jpabook.jpashop.domain.OrderItem;

import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.EntityTransaction;
import javax.persistence.Persistence;

public class JpaMain {
    public static void main(String[] args) {
        EntityManagerFactory emf = Persistence.createEntityManagerFactory(&quot;hello&quot;);
        EntityManager em = emf.createEntityManager();

        EntityTransaction tx = em.getTransaction();

        tx.begin();
        try {
            Order order = new Order();
            em.persist(order);

            // 방법 1 : 양방향 연관관계 매핑(JPQL에서 중요)
//            order.addOrderItem(new OrderItem());

            // 방법 2 : 단방향으로 처리해도 아무문제 x
            OrderItem orderItem = new OrderItem();
            orderItem.setOrder(order);

            em.persist(orderItem);

            tx.commit();
        } catch (Exception e) {
            tx.rollback();
        } finally {
            em.close();
        }

        emf.close();
}
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;핵심은 단방향으로 설계를 잘 하는게 중요하다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>JPA/자바 ORM 표준 JPA 프로그래밍</category>
      <category>inflearn</category>
      <category>jpa</category>
      <category>ORM</category>
      <category>spring</category>
      <category>springboot</category>
      <category>김영한</category>
      <category>인프런</category>
      <author>c0mmedes</author>
      <guid isPermaLink="true">https://c0mmedes.tistory.com/163</guid>
      <comments>https://c0mmedes.tistory.com/163#entry163comment</comments>
      <pubDate>Sat, 15 Jul 2023 16:25:44 +0900</pubDate>
    </item>
    <item>
      <title>[자바 ORM 표준 JPA 프로그래밍] [섹션 4] 엔티티 매핑</title>
      <link>https://c0mmedes.tistory.com/162</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;1. 객체와 테이블 매핑&lt;/b&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;객체와 테이블 매핑: @Entity, @Table&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;@Entity&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;@Entity가 붙은 클래스는 JPA가 관리&lt;/li&gt;
&lt;li&gt;JPA를 사용해서 테이블과 매핑할 클래스는 @Entity 필수&lt;/li&gt;
&lt;li&gt;기본 생성자 필수(파라미터가 없는 public 또는 protected 생성자)&lt;/li&gt;
&lt;li&gt;final, enum, interface, inner 클래스 사용X&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;less&quot;&gt;&lt;code&gt;@Entity
@Table(name = &quot;MBR&quot;)// MBR이라는 테이블과 매핑 -&amp;gt; INSERT INTO MBR ~public class Member {
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;2. 데이터베이스 스키마 자동 생성&lt;/b&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;DDL(CREATE, ALTER, DROP)을 애플리케이션 실행 시점에 자동 생성&lt;/li&gt;
&lt;li&gt;테이블 중심 -&amp;gt; 객체 중심&lt;/li&gt;
&lt;li&gt;데이터베이스 방언을 활용해서 데이터베이스에 맞는 적절한 DDL 생성&lt;/li&gt;
&lt;li&gt;이렇게 생성된 DDL은 개발 장비에서만 사용&lt;/li&gt;
&lt;li&gt;생성된 DDL은 운영서버에서는 사용하지 않거나, 적절히 다듬은 후 사용&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;속성&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;persistence.xml&lt;/p&gt;
&lt;pre class=&quot;applescript&quot;&gt;&lt;code&gt;&amp;lt;property name=&quot;hibernate.hbm2ddl.auto&quot; value=&quot;create&quot; /&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;create - 기존 테이블 삭제 후 다시 생성(DROP + CREATE)&lt;/li&gt;
&lt;li&gt;create-drop - create와 같으나 종료시점에 테이블 DROP&lt;/li&gt;
&lt;li&gt;update - 변경분만 반영(운영DB에는 사용하면 안됨)&lt;/li&gt;
&lt;li&gt;validate - 엔티티와 테이블이 정상 매핑되었는지만 확인&lt;/li&gt;
&lt;li&gt;none - 사용하지 않음&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;주의&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;운영 장비에는 절대 create, create-drop, update 사용 x&lt;/li&gt;
&lt;li&gt;개발 초기 단계는 create 또는 update&lt;/li&gt;
&lt;li&gt;테스트 서버는 update 또는 validate (여러명이서 개발하는 환경)&lt;/li&gt;
&lt;li&gt;스테이징과 운영 서버는 validate 또는 none&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;DDL 생성 기능&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Member.java&lt;/p&gt;
&lt;pre class=&quot;reasonml&quot;&gt;&lt;code&gt; @Column(unique = true, length = 10)
    private String name;
&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;제약조건 추가&lt;/li&gt;
&lt;li&gt;DDL 생성 기능은 DDL을 자동 생성할 때만 사용되고 JPA의 실행 로직에는 영향을 주지 않는다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;3. 필드와 컬럼 매핑&lt;/b&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;필드와 컬럼 매핑: @Column&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;매핑 어노테이션 정리&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;hibernate.hbm2ddl.auto&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;@Column - 컬럼 매핑
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;name - 필드와 매핑할 테이블의 컬럼 이름 (기본값 - 객체의 필드 이름)&lt;/li&gt;
&lt;li&gt;insertable, updatable - 등록, 변경 가능 여부 (기본값 - TRUE)&lt;/li&gt;
&lt;li&gt;nullable(DDL) - null 값의 허용 여부를 설정한다. false로 설정하면 DDL 생성 시에 not null 제약조건이 붙는다.&lt;/li&gt;
&lt;li&gt;unique(DDL) - @Table uniqueConstraints와 같지만 한 컬럼에 간단히 유니크 제약조건을 걸 때 사용한다. (키값이 이상하게 부여돼서 자주 사용하지 않고 @Table 속성에서 주로 씀)&lt;/li&gt;
&lt;li&gt;columnDefinition(DDL) - 데이터베이스 컬럼 정보를 직접 줄 수 있다. ex) varchar(100) default &amp;lsquo;EMPTY'&lt;/li&gt;
&lt;li&gt;length(DDL) - 문자 길이 제약조건, String 타입에만 사용한다. (기본값 - 255)&lt;/li&gt;
&lt;li&gt;precision, scale(DDL) - BigDecimal 타입에서 사용한다(BigInteger도 사용할 수 있다). precision은 소수점을 포함한 전체 자 릿수를, scale은 소수의 자릿수다. 참고로 double, float 타입에는 적용되지 않는다. 아주 큰 숫자나 정밀한 소수를 다루어야 할 때만 사용한다. (기본값 - precision=19, scale=2)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;@Temporal - 날짜 타입 매핑
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;TemporalType.DATE: 날짜, 데이터베이스 date 타입과 매핑 (예: 2013&amp;ndash;10&amp;ndash;11)&lt;/li&gt;
&lt;li&gt;TemporalType.TIME: 시간, 데이터베이스 time 타입과 매핑 (예: 11:11:11)&lt;/li&gt;
&lt;li&gt;TemporalType.TIMESTAMP: 날짜와 시간, 데이터베이 스 timestamp 타입과 매핑(예: 2013&amp;ndash;10&amp;ndash;11 11:11:11)&lt;/li&gt;
&lt;li&gt;참고: LocalDate, LocalDateTime을 사용할 때는 생략 가능(최신 하이버네이트 지원)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;@Enumerated - enum 타입 매핑
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;EnumType.ORDINAL(기본값): enum 순서를 데이터베이스에 저장&lt;/li&gt;
&lt;li&gt;EnumType.STRING: enum 이름을 데이터베이스에 저장&lt;/li&gt;
&lt;li&gt;ORDINAL 사용X &amp;rarr; 순서로 갱신하기 때문에 새로운 값이 추가되면 그게 다시 0이돼서&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;@Lob - BLOB, CLOB 매핑
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;@Lob에는 지정할 수 있는 속성이 없다.&lt;/li&gt;
&lt;li&gt;매핑하는 필드 타입이 문자면 CLOB 매핑, 나머지는 BLOB 매핑 &amp;bull; CLOB: String, char[], java.sql.CLOB &amp;bull; BLOB: byte[], java.sql. BLOB&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;@Transient - 특정 필드를 컬럼에 매핑하지 않음(매핑 무시), DB에서는 사용하지 않게(메모리에만 사용할 수 있게)&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;4. 기본 키 매핑&lt;/b&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;기본 키 매핑
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;자동 생성 - @GeneratedValue
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;IDENTITY: 데이터베이스에 위임, MYSQL
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;기본 키 생성을 데이터베이스에 위임&lt;/li&gt;
&lt;li&gt;주로 MySQL, PostgreSQL, SQL Server, DB2에서 사용 (예: MySQL의 AUTO_ INCREMENT)&lt;/li&gt;
&lt;li&gt;JPA는 보통 트랜잭션 커밋 시점에 INSERT SQL 실행&lt;/li&gt;
&lt;li&gt;AUTO_ INCREMENT는 데이터베이스에 INSERT SQL을 실행한 이후에 ID 값을 알 수 있음&lt;/li&gt;
&lt;li&gt;IDENTITY 전략은 em.persist() 시점에 즉시 INSERT SQL 실행하고 DB에서 식별자를 조회&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;less&quot;&gt;&lt;code&gt;@Entity
public class Member {
 @Id
 @GeneratedValue(strategy = GenerationType.IDENTITY)
 private Long id;
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;SEQUENCE: 데이터베이스 시퀀스 오브젝트 사용, ORACLE @SequenceGenerator 필요
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;데이터베이스 시퀀스는 유일한 값을 순서대로 생성하는 특별한 데이터베이스 오브젝트(예: 오라클 시퀀스)&lt;/li&gt;
&lt;li&gt;오라클, PostgreSQL, DB2, H2 데이터베이스에서 사용&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;less&quot;&gt;&lt;code&gt;@Entity
@SequenceGenerator(
 name = &amp;ldquo;MEMBER_SEQ_GENERATOR&quot;,
 sequenceName = &amp;ldquo;MEMBER_SEQ&quot;, //매핑할 데이터베이스 시퀀스 이름
 initialValue = 1, allocationSize = 1)
public class Member {
 @Id
 @GeneratedValue(strategy = GenerationType.SEQUENCE,
 generator = &quot;MEMBER_SEQ_GENERATOR&quot;)
 private Long id;
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;TABLE: 키 생성용 테이블 사용, 모든 DB에서 사용
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;@TableGenerator 필요&lt;/li&gt;
&lt;li&gt;키 생성 전용 테이블을 하나 만들어서 데이터베이스 시퀀스를 흉내내는 전략&lt;/li&gt;
&lt;li&gt;장점: 모든 데이터베이스에 적용 가능&lt;/li&gt;
&lt;li&gt;단점: 성능&lt;/li&gt;
&lt;li&gt;비주류&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;less&quot;&gt;&lt;code&gt;@Entity
@TableGenerator(
 name = &quot;MEMBER_SEQ_GENERATOR&quot;,
 table = &quot;MY_SEQUENCES&quot;,
 pkColumnValue = &amp;ldquo;MEMBER_SEQ&quot;, allocationSize = 1)
public class Member {
 @Id
 @GeneratedValue(strategy = GenerationType.TABLE,
 generator = &quot;MEMBER_SEQ_GENERATOR&quot;)
 private Long id;
&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;pgsql&quot;&gt;&lt;code&gt;create table MY_SEQUENCES (
 sequence_name varchar(255) not null,
 next_val bigint,
 primary key ( sequence_name )
)
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;AUTO: 방언에 따라 자동 지정, 기본값&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;직접 할당 - @Id&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;연관관계 매핑: @ManyToOne, @JoinColumn&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;권장하는 식별자 전략&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;기본 키 제약 조건: null 아님, 유일, 변하면 안된다.&lt;/li&gt;
&lt;li&gt;미래까지 이 조건을 만족하는 자연키는 찾기 어렵다. 대리키(대 체키)를 사용하자.&lt;/li&gt;
&lt;li&gt;예를 들어 주민등록번호도 기본 키로 적절하지 않다.&lt;/li&gt;
&lt;li&gt;권장: Long형 + 대체키 + 키 생성전략 사용&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;5. 실전 예제 -1. 요구사항 분석과 기본 매핑&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;요구사항 분석&lt;/b&gt;&lt;b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;회원은 상품을 주문할 수 있다.&lt;/li&gt;
&lt;li&gt;주문 시 여러 종류의 상품을 선택할 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;기능 목록&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;회원 기능
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;회원등록&lt;/li&gt;
&lt;li&gt;회원조회&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;상품 기능
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;상품등록&lt;/li&gt;
&lt;li&gt;상품수정&lt;/li&gt;
&lt;li&gt;상품조회&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;주문 기능
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;상품주문&lt;/li&gt;
&lt;li&gt;주문내역조회&lt;/li&gt;
&lt;li&gt;주문취소&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;도메인 모델 분석&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;회원과 주문의 관계: 회원은 여러 번 주문할 수 있다. (일대다)&lt;/li&gt;
&lt;li&gt;주문과 상품의 관계: 주문할 때 여러 상품을 선택할 수 있다. 반대로 같은 상품도 여러 번 주문될 수 있다. 주문상품 이라는 모델을 만들어서 다대다 관계를 일다대, 다대일 관계로 풀어냄&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;Untitled.png&quot; data-origin-width=&quot;573&quot; data-origin-height=&quot;198&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bi7KLC/btsnvYMNPRs/aBjxSuqoxJ5AYodNkyOOg1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bi7KLC/btsnvYMNPRs/aBjxSuqoxJ5AYodNkyOOg1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bi7KLC/btsnvYMNPRs/aBjxSuqoxJ5AYodNkyOOg1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbi7KLC%2FbtsnvYMNPRs%2FaBjxSuqoxJ5AYodNkyOOg1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;573&quot; height=&quot;198&quot; data-filename=&quot;Untitled.png&quot; data-origin-width=&quot;573&quot; data-origin-height=&quot;198&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;테이블 설계&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;Untitled (1).png&quot; data-origin-width=&quot;408&quot; data-origin-height=&quot;215&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bndFQ5/btsnvEAVJlh/phm07BqJFwqmen2SDJYKSK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bndFQ5/btsnvEAVJlh/phm07BqJFwqmen2SDJYKSK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bndFQ5/btsnvEAVJlh/phm07BqJFwqmen2SDJYKSK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbndFQ5%2FbtsnvEAVJlh%2Fphm07BqJFwqmen2SDJYKSK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;408&quot; height=&quot;215&quot; data-filename=&quot;Untitled (1).png&quot; data-origin-width=&quot;408&quot; data-origin-height=&quot;215&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;엔티티 설계와 매핑&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;Untitled (2).png&quot; data-origin-width=&quot;454&quot; data-origin-height=&quot;217&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bAu99N/btsnwl15ADC/Z31AgChKhjk9zcw4RAfGj1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bAu99N/btsnwl15ADC/Z31AgChKhjk9zcw4RAfGj1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bAu99N/btsnwl15ADC/Z31AgChKhjk9zcw4RAfGj1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbAu99N%2Fbtsnwl15ADC%2FZ31AgChKhjk9zcw4RAfGj1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;454&quot; height=&quot;217&quot; data-filename=&quot;Untitled (2).png&quot; data-origin-width=&quot;454&quot; data-origin-height=&quot;217&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;데이터 중심 설계의 문제점&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;현재 방식은 객체 설계를 테이블 설계에 맞춘 방식&lt;/li&gt;
&lt;li&gt;테이블의 외래키를 객체에 그대로 가져옴&lt;/li&gt;
&lt;li&gt;객체 그래프 탐색이 불가능&lt;/li&gt;
&lt;li&gt;참조가 없으므로 UML도 잘못됨&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;java&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;package jpabook.jpashop.domain;

import javax.persistence.*;
import java.time.LocalDateTime;

@Entity
@Table(name = &quot;ORDERS&quot;) // db의 예약어가 order인 경우가 있어서
public class Order {

    @Id @GeneratedValue
    @Column(name = &quot;ORDER_ID&quot;)
    private Long id;

    // 주문자명
    // 관계형DB를 객체에 만든 설계
    @Column(name = &quot;MEMBER_ID&quot;)
    private Long memberId;

    // 이게 객체지향적인 코드
//    Private Member member
//    public Private getMember() {
//        return Member;
//    }

    private LocalDateTime orderDate;

    @Enumerated(EnumType.STRING)
    private OrderStatus status;

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public Long getMemberId() {
        return memberId;
    }

    public void setMemberId(Long memberId) {
        this.memberId = memberId;
    }

    public LocalDateTime getOrderDate() {
        return orderDate;
    }

    public void setOrderDate(LocalDateTime orderDate) {
        this.orderDate = orderDate;
    }

    public OrderStatus getStatus() {
        return status;
    }

    public void setStatus(OrderStatus status) {
        this.status = status;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>JPA/자바 ORM 표준 JPA 프로그래밍</category>
      <category>inflearn</category>
      <category>jpa</category>
      <category>ORM</category>
      <category>spring</category>
      <category>springboot</category>
      <category>김영한</category>
      <category>인프런</category>
      <author>c0mmedes</author>
      <guid isPermaLink="true">https://c0mmedes.tistory.com/162</guid>
      <comments>https://c0mmedes.tistory.com/162#entry162comment</comments>
      <pubDate>Thu, 13 Jul 2023 23:23:41 +0900</pubDate>
    </item>
  </channel>
</rss>