<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>얼렁뚱땅 개발 블로그</title>
    <link>https://james-coding-study.tistory.com/</link>
    <description></description>
    <language>ko</language>
    <pubDate>Thu, 27 Aug 2026 12:33:45 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>h_jinnny</managingEditor>
    <item>
      <title>Java문법 startsWith</title>
      <link>https://james-coding-study.tistory.com/80</link>
      <description>&lt;h2 data-end=&quot;109&quot; data-start=&quot;86&quot; data-ke-size=&quot;size26&quot;&gt;1️⃣ startsWith()란?&lt;/h2&gt;
&lt;p data-end=&quot;162&quot; data-start=&quot;110&quot; data-ke-size=&quot;size16&quot;&gt;startsWith()는 &lt;b&gt;문자열이 특정 문자열로 시작하는지&lt;/b&gt;를 확인하는 메서드입니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;211&quot; data-start=&quot;164&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;182&quot; data-start=&quot;164&quot;&gt;반환 타입: boolean&lt;/li&gt;
&lt;li data-end=&quot;211&quot; data-start=&quot;183&quot;&gt;소속 클래스: java.lang.String&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-end=&quot;216&quot; data-start=&quot;213&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-end=&quot;230&quot; data-start=&quot;218&quot; data-ke-size=&quot;size26&quot;&gt;2️⃣ 기본 문법&lt;/h2&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1767009269776&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;String str = &quot;HelloWorld&quot;; boolean result = str.startsWith(&quot;Hello&quot;);&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;333&quot; data-start=&quot;314&quot; data-ke-size=&quot;size16&quot;&gt;✔ result &amp;rarr; true&lt;/p&gt;
&lt;hr data-end=&quot;338&quot; data-start=&quot;335&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-end=&quot;353&quot; data-start=&quot;340&quot; data-ke-size=&quot;size26&quot;&gt;3️⃣ 예제별 설명&lt;/h2&gt;
&lt;h3 data-end=&quot;381&quot; data-start=&quot;355&quot; data-ke-size=&quot;size23&quot;&gt;✅ 문자열이 특정 값으로 시작하는지 확인&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1767009285062&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;String url = &quot;/api/users&quot;; 
if (url.startsWith(&quot;/api&quot;)) { 
	System.out.println(&quot;API 요청입니다.&quot;); 
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;526&quot; data-start=&quot;493&quot; data-ke-size=&quot;size16&quot;&gt;➡️ REST API 라우팅, 필터, 인터셉터에서 자주 사용&lt;/p&gt;
&lt;hr data-end=&quot;531&quot; data-start=&quot;528&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-end=&quot;546&quot; data-start=&quot;533&quot; data-ke-size=&quot;size23&quot;&gt;✅ 대소문자 구분&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1767009331730&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;String text = &quot;Java&quot;; 
System.out.println(text.startsWith(&quot;java&quot;)); // false 
System.out.println(text.startsWith(&quot;Java&quot;)); // true&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;725&quot; data-start=&quot;690&quot; data-ke-size=&quot;size16&quot;&gt;⚠️ startsWith()는 &lt;b&gt;대소문자를 구분&lt;/b&gt;합니다.&lt;/p&gt;
&lt;hr data-end=&quot;730&quot; data-start=&quot;727&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-end=&quot;762&quot; data-start=&quot;732&quot; data-ke-size=&quot;size26&quot;&gt;4️⃣ 특정 위치부터 시작하는지 확인 (오버로딩)&lt;/h2&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1767009359293&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;boolean startsWith(String prefix, int toffset)&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3 data-end=&quot;829&quot; data-start=&quot;823&quot; data-ke-size=&quot;size23&quot;&gt;예제&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1767009370045&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;String str = &quot;HelloWorld&quot;; 
System.out.println(str.startsWith(&quot;World&quot;, 5)); // true&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;958&quot; data-start=&quot;927&quot; data-ke-size=&quot;size16&quot;&gt;✔ 인덱스 5부터 &quot;World&quot;가 시작하는지 확인&lt;/p&gt;
&lt;hr data-end=&quot;963&quot; data-start=&quot;960&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-end=&quot;985&quot; data-start=&quot;965&quot; data-ke-size=&quot;size26&quot;&gt;5️⃣ 실무에서 많이 쓰는 패턴&lt;/h2&gt;
&lt;h3 data-end=&quot;1004&quot; data-start=&quot;987&quot; data-ke-size=&quot;size23&quot;&gt;  권한 / 토큰 검사&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1767009390028&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;String authHeader = &quot;Bearer eyJhbGciOi...&quot;; 
if (authHeader.startsWith(&quot;Bearer &quot;)) { 
	String token = authHeader.substring(7); 
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;1210&quot; data-start=&quot;1149&quot; data-ke-size=&quot;size16&quot;&gt;➡️ JWT 인증 처리에서 매우 흔함&lt;br /&gt;(지금까지 하신 Spring + JWT 프로젝트랑 딱 맞는 예제예요)&lt;/p&gt;
&lt;hr data-end=&quot;1215&quot; data-start=&quot;1212&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-end=&quot;1233&quot; data-start=&quot;1217&quot; data-ke-size=&quot;size23&quot;&gt;  파일 확장자 체크&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1767009417344&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;String fileName = &quot;image.png&quot;; 
if (fileName.startsWith(&quot;image&quot;)) { 
	// 이미지 관련 처리 
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;hr data-end=&quot;1337&quot; data-start=&quot;1334&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-end=&quot;1376&quot; data-start=&quot;1339&quot; data-ke-size=&quot;size26&quot;&gt;6️⃣ startsWith() vs contains()&lt;/h2&gt;
&lt;div&gt;
&lt;div&gt;메서드의미
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-end=&quot;1472&quot; data-start=&quot;1377&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody data-end=&quot;1472&quot; data-start=&quot;1406&quot;&gt;
&lt;tr data-end=&quot;1438&quot; data-start=&quot;1406&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1423&quot; data-start=&quot;1406&quot;&gt;startsWith()&lt;/td&gt;
&lt;td data-end=&quot;1438&quot; data-start=&quot;1423&quot; data-col-size=&quot;sm&quot;&gt;&lt;b&gt;처음부터&lt;/b&gt; 일치&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;1472&quot; data-start=&quot;1439&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1454&quot; data-start=&quot;1439&quot;&gt;contains()&lt;/td&gt;
&lt;td data-end=&quot;1472&quot; data-start=&quot;1454&quot; data-col-size=&quot;sm&quot;&gt;문자열 &lt;b&gt;어디든 포함&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1767009431678&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&quot;HelloWorld&quot;.startsWith(&quot;World&quot;); // false 
&quot;HelloWorld&quot;.contains(&quot;World&quot;); // true&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;hr data-end=&quot;1575&quot; data-start=&quot;1572&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-end=&quot;1591&quot; data-start=&quot;1577&quot; data-ke-size=&quot;size26&quot;&gt;7️⃣ 주의사항 ⚠️&lt;/h2&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1767009442074&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;String str = null; str.startsWith(&quot;Hi&quot;); // ❌ NullPointerException&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;1684&quot; data-start=&quot;1672&quot; data-ke-size=&quot;size16&quot;&gt;✔ null 체크 필수&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1767009449710&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;if (str != null &amp;amp;&amp;amp; str.startsWith(&quot;Hi&quot;)) { ... }&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;hr data-end=&quot;1754&quot; data-start=&quot;1751&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-end=&quot;1769&quot; data-start=&quot;1756&quot; data-ke-size=&quot;size26&quot;&gt;8️⃣ 한 줄 요약&lt;/h2&gt;
&lt;blockquote data-end=&quot;1879&quot; data-start=&quot;1770&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;p data-end=&quot;1879&quot; data-start=&quot;1772&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;startsWith()는 문자열이 특정 접두사(prefix)로 시작하는지 검사하는 메서드&lt;/b&gt;이며,&lt;br /&gt;API 경로 처리, 인증 헤더 검사, 문자열 분기 처리에 매우 자주 사용됩니다.&lt;/p&gt;
&lt;/blockquote&gt;</description>
      <author>h_jinnny</author>
      <guid isPermaLink="true">https://james-coding-study.tistory.com/80</guid>
      <comments>https://james-coding-study.tistory.com/80#entry80comment</comments>
      <pubDate>Mon, 29 Dec 2025 20:57:41 +0900</pubDate>
    </item>
    <item>
      <title>Kafka의 분산처리</title>
      <link>https://james-coding-study.tistory.com/79</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;성능 개선: Kafka 기반 채팅 서비스 아키텍처 최적화 사례&lt;/b&gt;&lt;b&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;1. 문제 상황&lt;/b&gt;&lt;/h4&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;br /&gt;기존의 채팅 서비스에서는 모든 채팅방의 메시지가 하나의 Kafka 토픽과 하나의 파티션에서 처리되었습니다. 초기 구현에서는 단일 채널로도 정상적으로 동작했지만, 채팅방 수가 증가하면서 다음과 같은 문제가 발생했습니다:&lt;/h4&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;: 메모리 및 CPU 사용이 특정 시점에 집중되면서 성능 저하와 응답 시간 증가가 발생했습니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;스케일링 어려움&lt;/b&gt;: 새로운 채팅방이 추가될수록 기존 토픽의 부담이 커져 확장성이 떨어졌습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;2. 기존 구조와 한계&lt;/b&gt;&lt;/h4&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;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;3. 개선된 구조&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;새로운 아키텍처는 다음과 같이 설계되었습니다:&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;구분기존 구조개선된 구조&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style12&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 9.18605%;&quot; rowspan=&quot;2&quot;&gt;&lt;b&gt;구분&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 33.1395%;&quot; rowspan=&quot;2&quot;&gt;&lt;b&gt;기존 구조&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 57.5581%;&quot; rowspan=&quot;2&quot;&gt;&lt;b&gt;개선된 구조&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 9.18605%;&quot;&gt;&lt;b&gt;처리 방식&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 33.1395%;&quot;&gt;모든 채팅방을 하나의 토픽, 하나의 파티션에서 처리&lt;/td&gt;
&lt;td style=&quot;width: 57.5581%;&quot;&gt;채팅방 10개당 1개의 토픽 사용. 각 토픽은 10개의 파티션으로 구성, 채팅방별로 파티션 할당&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 9.18605%;&quot;&gt;&lt;b&gt;토픽 번호&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 33.1395%;&quot;&gt;N/A&lt;/td&gt;
&lt;td style=&quot;width: 57.5581%;&quot;&gt;roomId / 10 + 1 (예: chatTopic1, chatTopic2, ...)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 9.18605%;&quot;&gt;&lt;b&gt;파티션 번호&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 33.1395%;&quot;&gt;N/A&lt;/td&gt;
&lt;td style=&quot;width: 57.5581%;&quot;&gt;roomId % 10 (예: 0, 1, 2, ...)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 9.18605%;&quot;&gt;&lt;b&gt;미리 생성&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 33.1395%;&quot;&gt;N/A&lt;/td&gt;
&lt;td style=&quot;width: 57.5581%;&quot;&gt;기존 토픽의 5번째 파티션 사용 시 다음 토픽 미리 생성&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 9.18605%;&quot;&gt;&lt;b&gt;예시&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 33.1395%;&quot;&gt;N/A&lt;/td&gt;
&lt;td style=&quot;width: 57.5581%;&quot;&gt;roomId가 13인 경우 &amp;rarr; 토픽: chatTopic2, 파티션: 3&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;4. 성능 개선 및 기대 효과&lt;/b&gt;&lt;/h4&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;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;b&gt;메모리 및 CPU 자원 최적화&lt;/b&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;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;/li&gt;
&lt;/ul&gt;
&lt;/li&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;/li&gt;
&lt;/ul&gt;
&lt;/li&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;/li&gt;
&lt;li&gt;시스템의 전체 응답성이 향상됨.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;</description>
      <author>h_jinnny</author>
      <guid isPermaLink="true">https://james-coding-study.tistory.com/79</guid>
      <comments>https://james-coding-study.tistory.com/79#entry79comment</comments>
      <pubDate>Sun, 24 Nov 2024 18:08:38 +0900</pubDate>
    </item>
    <item>
      <title>kafka</title>
      <link>https://james-coding-study.tistory.com/78</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Kafka란?&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Apache Kafka는 고성능, 내구성, 그리고 확장 가능한 분산 스트리밍 플랫폼이다. Kafka는 데이터 파이프라인을 구축하고 실시간 데이터 스트리밍을 처리하는 데 매우 적합하다.&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;프로듀서(Producer)&lt;/b&gt;: 메시지를 생성하여 Kafka 토픽으로 전송하는 역할을 한다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;컨슈머(Consumer)&lt;/b&gt;: Kafka 토픽에서 메시지를 읽어오는 역할을 한다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;브로커(Broker)&lt;/b&gt;: Kafka 서버로, 토픽과 메시지를 저장하고 관리한다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;토픽(Topic)&lt;/b&gt;: 메시지가 게시되는 논리적 채널이다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Kafka는 다음과 같은 경우에 많이 사용된다:&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;데이터 파이프라인&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;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;Kafka의 주요 특징&lt;/b&gt;&lt;/h3&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;: Kafka는 분산형 구조로 설계되어 있어, 여러 서버(브로커)에서 데이터를 저장하고 처리할 수 있다. 이로 인해 높은 가용성과 확장성을 제공한다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;높은 처리량&lt;/b&gt;: Kafka는 대규모 데이터 스트리밍을 처리할 수 있는 높은 처리량을 자랑한다. 이를 통해 초당 수백만 개의 메시지를 처리할 수 있다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;내구성&lt;/b&gt;: Kafka는 데이터를 복제하여 여러 브로커에 저장하므로, 서버 장애가 발생해도 데이터가 손실되지 않는다. 데이터의 내구성을 보장한다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;실시간 데이터 처리&lt;/b&gt;: Kafka는 실시간 데이터 처리를 지원하여, 데이터가 생성되는 즉시 소비자에게 전달할 수 있다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;확장성&lt;/b&gt;: Kafka는 새로운 브로커를 추가하여 수평적으로 확장할 수 있다. 이를 통해 데이터 처리 용량을 쉽게 늘릴 수 있다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;높은 가용성&lt;/b&gt;: Kafka 클러스터는 데이터의 복제와 자동 복구 기능을 통해 높은 가용성을 제공한다.&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;Kafka를 사용하는 이유&lt;/b&gt;&lt;/h3&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;: 대규모 데이터 처리가 필요한 시스템에서 Kafka는 높은 처리량과 낮은 지연 시간을 제공하여, 대량의 데이터를 효율적으로 관리할 수 있다.&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;li&gt;&lt;b&gt;데이터 통합&lt;/b&gt;: 다양한 시스템과 애플리케이션 간의 데이터 통합을 지원한다. Kafka는 다양한 데이터 소스와 소비자 간의 데이터 흐름을 중재할 수 있다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;확장성&lt;/b&gt;: 시스템이 성장함에 따라 처리 용량을 쉽게 확장할 수 있다. Kafka 클러스터에 브로커를 추가하여 수평적으로 확장할 수 있다.&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;Kafka의 사용 사례&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;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;li&gt;&lt;b&gt;실시간 분석&lt;/b&gt;: 실시간으로 데이터 분석을 수행하여 인사이트를 얻는 데 활용된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;Docker로 Kafka 설정&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Docker를 사용하면 Kafka를 쉽게 설정하고 실행할 수 있다. Docker Compose 파일을 작성하여 Kafka와 Zookeeper를 설정한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;이 파일을 통해 Zookeeper와 Kafka 브로커를 Docker 컨테이너로 실행할 수 있다.&lt;/span&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;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1952&quot; data-origin-height=&quot;476&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/P9ZHg/btsIUe8FcyG/mkoS5HXWVJHrKRamGz55X0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/P9ZHg/btsIUe8FcyG/mkoS5HXWVJHrKRamGz55X0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/P9ZHg/btsIUe8FcyG/mkoS5HXWVJHrKRamGz55X0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FP9ZHg%2FbtsIUe8FcyG%2FmkoS5HXWVJHrKRamGz55X0%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;1952&quot; height=&quot;476&quot; data-origin-width=&quot;1952&quot; data-origin-height=&quot;476&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;그렇다면 Zookeeper와 브로커는 뭘까??&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;Kafka의 주요 구성 요소&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;1. &lt;b&gt;Zookeeper&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Zookeeper는 분산 애플리케이션을 위한 중앙 집중형 서비스로, 구성 정보, 네이밍, 동기화, 그룹 서비스를 제공한다. Kafka는 Zookeeper를 사용하여 브로커와 클러스터 메타데이터를 관리하고, 브로커 간의 협업을 돕는다. Zookeeper는 클러스터의 상태를 유지하고, 새로운 브로커가 추가되거나 실패한 브로커를 감지하여 이를 다른 브로커에 통지하는 역할을 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;2. &lt;b&gt;브로커(Broker)&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;브로커는 Kafka 서버를 의미하며, 메시지를 저장하고 관리하는 역할을 한다. 브로커는 여러 개의 토픽을 호스팅하며, 각각의 토픽은 여러 개의 파티션으로 나뉘어진다. 브로커는 각 파티션의 리더와 팔로워를 관리하며, 메시지의 복제와 분산 처리를 수행한다. 클러스터 내의 브로커들은 서로 협력하여 고가용성과 내구성을 제공한다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;Spring Boot에서의 kafka는?&lt;/b&gt;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;Kafka 프로듀서 작성&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Kafka 프로듀서는 메시지를 생성하여 Kafka 토픽으로 전송하는 역할을 한다. Spring Boot에서 Kafka 프로듀서를 작성하려면 KafkaTemplate을 사용하면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1722778462267&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import org.springframework.kafka.core.KafkaTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class KafkaProducer {

    @Autowired
    private KafkaTemplate&amp;lt;String, String&amp;gt; kafkaTemplate;

    private static final String TOPIC = &quot;test_topic&quot;;

    @GetMapping(&quot;/send&quot;)
    public String sendMessage(@RequestParam(&quot;message&quot;) String message) {
        kafkaTemplate.send(TOPIC, message);
        return &quot;Message sent to Kafka topic&quot;;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;div&gt;&lt;b&gt;Kafka 컨슈머 작성&lt;/b&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Kafka 컨슈머는 Kafka 토픽에서 메시지를 읽어오는 역할을 한다. Spring Boot에서 Kafka 컨슈머를 작성하려면 @KafkaListener를 사용하면 된다.&lt;/p&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;pre id=&quot;code_1722778497164&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import org.springframework.kafka.annotation.KafkaListener;
import org.springframework.stereotype.Service;

@Service
public class KafkaConsumer {

    @KafkaListener(topics = &quot;test_topic&quot;, groupId = &quot;group_id&quot;)
    public void consume(String message) {
        System.out.println(&quot;Consumed message: &quot; + message);
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;클라이언트가 브라우저에서 &quot;http://localhost:8080/send?message=HelloKafka&quot;를 접속하면&amp;nbsp;&quot;HelloKafka&quot; 메시지가 Kafka 토픽에 전송된다. 컨슈머가 이 메시지를 읽어 콘솔에 출력하는 것을 확인할 수 있다.&lt;/p&gt;
&lt;pre id=&quot;code_1722778783963&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Consumed message: HelloKafka&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Back-End</category>
      <author>h_jinnny</author>
      <guid isPermaLink="true">https://james-coding-study.tistory.com/78</guid>
      <comments>https://james-coding-study.tistory.com/78#entry78comment</comments>
      <pubDate>Sun, 4 Aug 2024 22:40:14 +0900</pubDate>
    </item>
    <item>
      <title>Hibernate Naming Strategies</title>
      <link>https://james-coding-study.tistory.com/77</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;혼자 공부할겸 프로젝트를 진행하다가 예상치못한 오류에 막혀서 많은 시간을 소요하였다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;데이터베이스의 테이블에서 값을 전혀 불러오지 못하는 문제였다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아무리 찾아봐도 문제를 찾지 못하다가 혹시나 하는 마음에 모든 테이블을 조회해보았고 생성한 적 없는 테이블이 만들어져있는 것을 봤다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기존에 만든 테이블은 &lt;span style=&quot;color: #006dd7;&quot;&gt;orderItems&lt;/span&gt;인데 새로 생성된 테이블은 &lt;span style=&quot;color: #006dd7;&quot;&gt;order_items&lt;/span&gt;가 있었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;분명 엔티티에서 table(name=&quot;orderItems&quot;)로 작성해서 orderItems테이블과 매핑이 되어있을 것이라고 생각했는데 order_items테이블이 새로 생기며 여기와 매핑을 하고 있던 것이다.&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;span style=&quot;color: #ee2323;&quot;&gt;Hibernate Naming Strategies&lt;span style=&quot;color: #000000;&quot;&gt;의&amp;nbsp;&lt;/span&gt;&lt;/span&gt; &lt;span style=&quot;color: #ee2323;&quot;&gt;Physical Naming Strategy&lt;/span&gt;&lt;/b&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;Hibernate Naming Strategies&amp;nbsp;&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Naming Strategies는 Hibernate가 엔티티 클래스의 필드와 데이터베이스 테이블의 컬럼을 매핑하는 방식을 정의한다. 이를 통해 코드를 간결하게 유지하고, 일관된 네이밍 규칙을 적용할 수 있다. Hibernate는 두 가지 주요 네이밍 전략을 제공한다&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;Physical Naming Strategy&lt;/b&gt;: 데이터베이스의 실제 테이블 및 컬럼 이름을 결정한다. 논리적 이름을 실제 데이터베이스에 적용할 물리적 이름으로 변환한다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Implicit Naming Strategy&lt;/b&gt;: 명시적으로 지정되지 않은 테이블 및 컬럼 이름을 결정한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;1. Physical Naming Strategy&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;PhysicalNamingStrategy는 Java 엔티티 필드 이름을 데이터베이스의 실제 테이블 및 컬럼 이름으로 변환하는 방법을 정의한다.&lt;/p&gt;
&lt;pre id=&quot;code_1719476823298&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@Entity
@Table(name = &quot;orderItems&quot;)
public class OrderItem {
    @Id
    private Long id;
    private String productName;
}&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;논리적 이름 지정&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;@Table(name = &quot;orderItems&quot;)에 의해 논리적 테이블 이름은 orderItems로 지정됩니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;물리적 이름 변환&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;PhysicalNamingStrategyStandardImpl가 논리적 이름 orderItems를 물리적 이름 order_items로 변환합니다.&lt;/li&gt;
&lt;li&gt;즉 카멜케이스를 스네이크케이스로 바꾼다고 볼 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;2. Implicit Naming Strategy&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ImplicitNamingStrategy는 명시적으로 지정되지 않은 경우 기본값으로 사용될 이름을 정의한다. 기본적으로 제공되는 구현은 다음과 같다:&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;ImplicitNamingStrategyLegacyJpaImpl&lt;/b&gt;: JPA의 기본 네이밍 규칙을 따른다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;ImplicitNamingStrategyComponentPathImpl&lt;/b&gt;: 필드명을 기반으로 명명한다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;ImplicitNamingStrategyJpaCompliantImpl&lt;/b&gt;: JPA 2.0 명명 규칙을 따른다.&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1719384202920&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@Entity
@Getter
@Setter
public class UserAccount {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    
    private String userName;
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ImplicitNamingStrategyLegacyJpaImpl을 사용할 경우, UserAccount 엔티티는 user_account 테이블에 매핑되고, userName 필드는 user_name 컬럼에 매핑된다.&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;size18&quot;&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;&lt;b&gt;모두들 테이블명과 컬럼명에 잘 매핑했다고 생각하고 그냥 넘어가지말고 다시한번 확인해보며 시간을 줄이면 좋을거같다&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;</description>
      <category>Back-End/Spring</category>
      <author>h_jinnny</author>
      <guid isPermaLink="true">https://james-coding-study.tistory.com/77</guid>
      <comments>https://james-coding-study.tistory.com/77#entry77comment</comments>
      <pubDate>Wed, 26 Jun 2024 15:46:59 +0900</pubDate>
    </item>
    <item>
      <title>[AWS] EC2와 RDS 설정 및 프로젝트 배포</title>
      <link>https://james-coding-study.tistory.com/76</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;AWS EC2와 RDS 인스턴스를 설정하고, GitHub에서 프로젝트를 클론하여 빌드하고 배포하는 방법을 단계별로 안내하고자 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또한, S3를 이용한 빌드 및 배포 방법도 소개할 것이다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;1. AWS EC2 인스턴스 설정&lt;/b&gt;&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;1.1. EC2 인스턴스 생성&lt;/b&gt;&lt;/h4&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;AWS 콘솔&lt;/b&gt;에 로그인하고 &lt;b&gt;EC2 대시보드&lt;/b&gt;로 이동한다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;인스턴스 시작&lt;/b&gt; 버튼을 클릭한다.&lt;/li&gt;
&lt;li&gt;**Amazon Machine Image (AMI)**에서 원하는 OS를 선택한다. (예: Amazon Linux 2)&lt;/li&gt;
&lt;li&gt;&lt;b&gt;인스턴스 유형&lt;/b&gt;을 선택한다. (예: t2.micro)&lt;/li&gt;
&lt;li&gt;&lt;b&gt;인스턴스 세부 정보 구성&lt;/b&gt;, &lt;b&gt;스토리지 추가&lt;/b&gt; 및 &lt;b&gt;태그 추가&lt;/b&gt; 단계를 기본값으로 둔다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;보안 그룹 구성&lt;/b&gt; 단계에서, 새로운 보안 그룹을 생성하고 HTTP(80) 및 SSH(22) 포트를 허용한다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;검토 및 시작&lt;/b&gt; 버튼을 클릭한 후 &lt;b&gt;시작&lt;/b&gt; 버튼을 클릭한다.&lt;/li&gt;
&lt;li&gt;새로운 키 페어를 생성하거나 기존 키 페어를 선택하여 다운로드한다.&lt;/li&gt;
&lt;/ol&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;1.2. EC2 인스턴스에 접속&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;터미널이나 CMD를 열고, 인스턴스 생성 시 다운로드한 키 페어를 사용하여 SSH로 접속한다:&lt;/p&gt;
&lt;pre id=&quot;code_1718127602652&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;chmod 400 your-key-pair.pem 
ssh -i &quot;your-key-pair.pem&quot; ec2-user@your-ec2-public-ip&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;1.3. 시스템 업데이트 및 필수 패키지 설치&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;EC2 인스턴스에 접속한 후, 시스템을 업데이트하고 필요한 패키지를 설치한다:&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1718127733527&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;yum list installed
sudo yum update

sudo yum install git
git config --global user.name &quot;(git 이름)&quot;
git config --global user.email &quot;(git 이메일)&quot;
sudo yum install -y java-21-amazon-corretto-devel&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;1.4. AWS CLI 설치 및 aws configure 설정&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;1.4.1. AWS CLI(AWS Command Line Interface) 설치&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ec2는 리눅스 기반이므로 아래의 명령어를 진행하여 설치한다&lt;/p&gt;
&lt;pre id=&quot;code_1718160333744&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;curl &quot;https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip&quot; -o &quot;awscliv2.zip&quot;
unzip awscliv2.zip
sudo ./aws/install&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;&lt;b&gt;1.4.2.&lt;span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;b&gt;aws configure 설정&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1718160660932&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;aws configure

AWS Access Key ID [None]: 해당 사용자의 accessKey의 Id를 입력
AWS Secret Access Key [None]: 해당 사용자의 Secret access key를 입력
Default region name [None]: ap-northeast-2
Default output format [None]: json&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;2. AWS RDS 인스턴스 설정&lt;/b&gt;&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;2.1. RDS 인스턴스 생성&lt;/b&gt;&lt;/h4&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;AWS 콘솔&lt;/b&gt;에 로그인하고 &lt;b&gt;RDS 대시보드&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;li&gt;데이터베이스 엔진으로 &lt;b&gt;MySQL&lt;/b&gt;을 선택한다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;템플릿&lt;/b&gt;을 선택한다. (예: 프리 티어)&amp;nbsp; &lt;s&gt;다른거 쓰면 과금.....&lt;/s&gt;&lt;/li&gt;
&lt;li&gt;데이터베이스 인스턴스 식별자, 마스터 사용자 이름 및 비밀번호를 설정한다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;DB 인스턴스 크기&lt;/b&gt; 및 &lt;b&gt;스토리지&lt;/b&gt; 설정을 완료한다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;연결&lt;/b&gt; 설정에서 기존 VPC를 선택하고, &lt;b&gt;퍼블릭 액세스&lt;/b&gt;를 허용한다.&lt;/li&gt;
&lt;li&gt;보안 그룹을 설정하여 EC2 인스턴스에서 MySQL 포트(3306)에 접근할 수 있도록 허용한다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;데이터베이스 생성&lt;/b&gt; 버튼을 클릭하여 RDS 인스턴스를 생성한다.&lt;/li&gt;
&lt;/ol&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;2.2. RDS 보안 그룹 설정&lt;/b&gt;&lt;/h4&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;EC2 대시보드&lt;/b&gt;로 이동하여 &lt;b&gt;보안 그룹&lt;/b&gt;을 클릭한다.&lt;/li&gt;
&lt;li&gt;RDS 인스턴스와 연결된 보안 그룹을 선택한다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;인바운드 규칙 편집&lt;/b&gt;을 클릭하여, &lt;b&gt;규칙 추가&lt;/b&gt; 버튼을 누른다.&lt;/li&gt;
&lt;li&gt;유형: &lt;b&gt;MySQL/Aurora&lt;/b&gt;, 프로토콜: &lt;b&gt;TCP&lt;/b&gt;, 포트 범위: &lt;b&gt;3306&lt;/b&gt;, 소스: &lt;b&gt;내 IP&lt;/b&gt; 또는 EC2 인스턴스에서 MySQL 포트(3306)에 접근할 수 있도록 &lt;b&gt;VPC의 &lt;span style=&quot;background-color: #fafafa; color: #16191f; text-align: start;&quot;&gt;IPv4 CIDR&lt;/span&gt;&lt;/b&gt;&lt;span style=&quot;background-color: #fafafa; color: #16191f; text-align: start;&quot;&gt;을&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #545b64; text-align: start;&quot;&gt;&amp;nbsp;등록해준다&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;저장&lt;/b&gt; 버튼을 클릭하여 변경 사항을 저장한다.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;3120&quot; data-origin-height=&quot;860&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ddezl1/btsHVVPswlz/sVKDNkD5p1l7dAZMW7nh6k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ddezl1/btsHVVPswlz/sVKDNkD5p1l7dAZMW7nh6k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ddezl1/btsHVVPswlz/sVKDNkD5p1l7dAZMW7nh6k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fddezl1%2FbtsHVVPswlz%2FsVKDNkD5p1l7dAZMW7nh6k%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;3120&quot; height=&quot;860&quot; data-origin-width=&quot;3120&quot; data-origin-height=&quot;860&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;3. 프로젝트 설정 및 배포&lt;/b&gt;&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;3.1. 로컬 컴퓨터에서 S3로 빌드 및 배포&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;3.1.1. Git 리포지토리 클론 및 빌드&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;로컬 컴퓨터에서 GitHub 프로젝트를 클론하고 빌드한다&lt;/p&gt;
&lt;pre id=&quot;code_1718128475222&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;git clone https://github.com/your-username/your-repository.git
cd your-repository
./gradlew build&lt;/code&gt;&lt;/pre&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;빌드가 완료되면, build/libs 디렉토리에 JAR 파일이 생성된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;3.1.2. S3 버킷 생성 및 JAR 파일 업로드&lt;/b&gt;&lt;b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;1. S3 버킷 생성&lt;/b&gt;:&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1718128542286&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;aws s3 mb s3://your-unique-bucket-name&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&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;2. JAR 파일 업로드&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1718128577954&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;aws s3 cp ./build/libs/your-application.jar s3://your-unique-bucket-name&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;3.1.3. EC2에서 JAR 파일 다운로드 및 실행&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;EC2 인스턴스에서 S3로부터 JAR 파일을 다운로드하고 실행한다&lt;/p&gt;
&lt;pre id=&quot;code_1718128607838&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;aws s3 cp s3://your-unique-bucket-name/your-application.jar .
java -jar your-application.jar&lt;/code&gt;&lt;/pre&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;3.2. EC2에서 바로 클론 및 빌드&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;3.2.1. Git 리포지토리 클론 및 빌드&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;EC2 인스턴스에서 GitHub 프로젝트를 클론하고 빌드한다&lt;/p&gt;
&lt;pre id=&quot;code_1718128652835&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;git clone https://github.com/your-username/your-repository.git
cd your-repository
./gradlew build&lt;/code&gt;&lt;/pre&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;3.2.2. 애플리케이션 실행&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;빌드가 완료되면, build/libs 디렉토리에 JAR 파일이 생성된다. 이 파일을 실행한다&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1718128677303&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;java -jar build/libs/your-application.jar&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;4. application.yml 설정&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;EC2 인스턴스에서 application.yml 파일을 설정하여 RDS에 연결한다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;i&gt;(뒤늦게 작성되어있지만 프로젝트를 클론하고 빌드하기 전에 미리 다 설정을 해놔야 된다!!!)&lt;/i&gt;&lt;/b&gt;&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1718128724149&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;spring:
  datasource:
    url: jdbc:mysql://your-rds-endpoint:3306/your-database-name
    username: ${DB_USERNAME}
    password: ${DB_PASSWORD}
  jpa:
    hibernate:
      ddl-auto: update
    show-sql: true
    database-platform: org.hibernate.dialect.MySQL5Dialect&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;your-rds-endpoint, your-database-name, your-rds-username, your-rds-password를 실제 RDS 인스턴스의 정보로 교체한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위는 username과, password를 &lt;b&gt;환경변수&lt;/b&gt;로 지정하였다.(&lt;span style=&quot;color: #ee2323;&quot;&gt;보안을 위해서 환경변수로 지정하는 것이 바람직함&lt;/span&gt;)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;환경변수를 로컬이나 ec2 인스턴스에서 사용하기 위해서는 해당하는 이름으로 값을 지정해줘야한다.&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1718161388720&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;//vi 편집기를 통해 zsh파일을 열어준다
vi ~/.zshrc

//맨 아래에
export USERNAME=DB 유저 이름
export PASSWORD=DB 유저 비밀번호&lt;/code&gt;&lt;/pre&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;AWS EC2와 RDS를 설정하고, GitHub에서 프로젝트를 클론하여 배포하는 방법을 정리하였음.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;ec2에서 바로 클론해서 빌드 하는 방식이랑 로컬에서 클론하고 빌드한 후 s3에 업로드한 후 ec2에서 다운받아서 빌드하고 배포하는 과정 두가지를 나누어 정리했음!!&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;application.yml은 클론하고 빌드하기 전에 미리 작성해두자!!&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;* 자바스크립트 파일에 XMLHttpRequest를 열 때 url을 작성해야되는데 인스턴스를 중지시켰다가 다시 실행시키면 공개ip가 변경되므로 꼭 자바스크립트에서도 변경을 해주고 위의 과정을 실행시키자!!&lt;/span&gt;&lt;/p&gt;</description>
      <category>Back-End</category>
      <author>h_jinnny</author>
      <guid isPermaLink="true">https://james-coding-study.tistory.com/76</guid>
      <comments>https://james-coding-study.tistory.com/76#entry76comment</comments>
      <pubDate>Wed, 12 Jun 2024 11:56:05 +0900</pubDate>
    </item>
    <item>
      <title>관계 매핑 전략(@OneToMany, @ManyToOne, @OneToOne, @ManyToMany), 상속 매핑 전략 (SINGLE_TABLE, JOINED, TABLE_PER_CLASS)</title>
      <link>https://james-coding-study.tistory.com/74</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;Java Persistence API (JPA)는 객체 관계 매핑(ORM) 기술을 통해 객체 지향 프로그래밍 언어의 객체를 관계형 데이터베이스의 테이블에 매핑한다. JPA에서는 다양한 엔티티 간의 관계를 정의할 수 있다. 본 글에서는 JPA에서의 @OneToMany, @ManyToOne, @OneToOne, @ManyToMany에 대해 설명하고, 각각의 관계에서 데이터를 저장, 수정, 삭제하는 예시를 다룰 것이다. 또한 JPA의 상속 매핑 전략에 대해서도 자세히 살펴보자.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;엔티티 간의 관계&lt;/b&gt;&lt;/h2&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;@OneToMany와 @ManyToOne&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;@OneToMany와 @ManyToOne 관계는 가장 흔히 사용되는 관계 중 하나로, 하나의 엔티티가 여러 엔티티와 관계를 맺는 경우이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&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;b&gt;Country&lt;/b&gt;: 여러 &lt;b&gt;City&lt;/b&gt;를 가질 수 있다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;City&lt;/b&gt;: 하나의 &lt;b&gt;Country&lt;/b&gt;에 속할 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1717029081908&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@Entity
public class Country {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private String name;

    @OneToMany(mappedBy = &quot;country&quot;, cascade = CascadeType.ALL, orphanRemoval = true)
    private List&amp;lt;City&amp;gt; cities = new ArrayList&amp;lt;&amp;gt;();

    // Getter, Setter, Constructor
}

@Entity
public class City {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private String name;

    @ManyToOne
    @JoinColumn(name = &quot;country_id&quot;)
    private Country country;

    // Getter, Setter, Constructor
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;데이터 저장, 수정, 삭제 예시&lt;/b&gt;&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1717029110003&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public void saveCountryAndCities(EntityManager em) {
    em.getTransaction().begin();

    Country country = new Country();
    country.setName(&quot;USA&quot;);

    City city1 = new City();
    city1.setName(&quot;New York&quot;);
    city1.setCountry(country);

    City city2 = new City();
    city2.setName(&quot;Los Angeles&quot;);
    city2.setCountry(country);

    country.getCities().add(city1);
    country.getCities().add(city2);

    em.persist(country);
    em.getTransaction().commit();
}

public void updateCity(EntityManager em, Long cityId) {
    em.getTransaction().begin();
    City city = em.find(City.class, cityId);
    if (city != null) {
        city.setName(&quot;San Francisco&quot;);
    }
    em.getTransaction().commit();
}

public void deleteCountry(EntityManager em, Long countryId) {
    em.getTransaction().begin();
    Country country = em.find(Country.class, countryId);
    if (country != null) {
        em.remove(country);
    }
    em.getTransaction().commit();
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;@OneToOne&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;@OneToOne 관계는 하나의 엔티티가 다른 하나의 엔티티와 1:1로 연결되는 경우이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&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;b&gt;User&lt;/b&gt;: 하나의 &lt;b&gt;Profile&lt;/b&gt;을 가질 수 있다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Profile&lt;/b&gt;: 하나의 &lt;b&gt;User&lt;/b&gt;에 속할 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1717029166749&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@Entity
public class User {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private String username;

    @OneToOne(cascade = CascadeType.ALL)
    @JoinColumn(name = &quot;profile_id&quot;)
    private Profile profile;

    // Getter, Setter, Constructor
}

@Entity
public class Profile {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private String bio;

    // Getter, Setter, Constructor
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;데이터 저장, 수정, 삭제 예시&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1717029187756&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public void saveUserAndProfile(EntityManager em) {
    em.getTransaction().begin();

    User user = new User();
    user.setUsername(&quot;johndoe&quot;);

    Profile profile = new Profile();
    profile.setBio(&quot;Software Developer&quot;);

    user.setProfile(profile);

    em.persist(user);
    em.getTransaction().commit();
}

public void updateProfile(EntityManager em, Long profileId) {
    em.getTransaction().begin();
    Profile profile = em.find(Profile.class, profileId);
    if (profile != null) {
        profile.setBio(&quot;Senior Software Developer&quot;);
    }
    em.getTransaction().commit();
}

public void deleteUser(EntityManager em, Long userId) {
    em.getTransaction().begin();
    User user = em.find(User.class, userId);
    if (user != null) {
        em.remove(user);
    }
    em.getTransaction().commit();
}&lt;/code&gt;&lt;/pre&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;@ManyToMany&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;@ManyToMany 관계는 여러 엔티티가 서로 다수와 연결될 수 있는 경우이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&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;b&gt;Student&lt;/b&gt;: 여러 &lt;b&gt;Course&lt;/b&gt;를 수강할 수 있다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Course&lt;/b&gt;: 여러 &lt;b&gt;Student&lt;/b&gt;가 수강할 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;pre id=&quot;code_1717029222875&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@Entity
public class Student {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private String name;

    @ManyToMany
    @JoinTable(
        name = &quot;student_course&quot;,
        joinColumns = @JoinColumn(name = &quot;student_id&quot;),
        inverseJoinColumns = @JoinColumn(name = &quot;course_id&quot;)
    )
    private Set&amp;lt;Course&amp;gt; courses = new HashSet&amp;lt;&amp;gt;();

    // Getter, Setter, Constructor
}

@Entity
public class Course {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private String title;

    @ManyToMany(mappedBy = &quot;courses&quot;)
    private Set&amp;lt;Student&amp;gt; students = new HashSet&amp;lt;&amp;gt;();

    // Getter, Setter, Constructor
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;데이터 저장, 수정, 삭제 예시&lt;/b&gt;&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1717029262356&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public void saveStudentAndCourses(EntityManager em) {
    em.getTransaction().begin();

    Student student = new Student();
    student.setName(&quot;Alice&quot;);

    Course course1 = new Course();
    course1.setTitle(&quot;Mathematics&quot;);

    Course course2 = new Course();
    course2.setTitle(&quot;Physics&quot;);

    student.getCourses().add(course1);
    student.getCourses().add(course2);

    course1.getStudents().add(student);
    course2.getStudents().add(student);

    em.persist(student);
    em.getTransaction().commit();
}

public void updateCourseTitle(EntityManager em, Long courseId) {
    em.getTransaction().begin();
    Course course = em.find(Course.class, courseId);
    if (course != null) {
        course.setTitle(&quot;Advanced Mathematics&quot;);
    }
    em.getTransaction().commit();
}

public void deleteStudent(EntityManager em, Long studentId) {
    em.getTransaction().begin();
    Student student = em.find(Student.class, studentId);
    if (student != null) {
        em.remove(student);
    }
    em.getTransaction().commit();
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;엔티티 상속&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;JPA는 엔티티 간의 상속 관계를 정의할 수 있다. 주요 상속 전략으로는 SINGLE_TABLE, JOINED, TABLE_PER_CLASS가 있다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;SINGLE_TABLE 전략&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;모든 엔티티를 하나의 테이블에 저장하고, 구분 컬럼을 사용하여 각 엔티티 유형을 식별하는 전략이다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;예시&lt;/h4&gt;
&lt;pre id=&quot;code_1717029290393&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@Entity
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(name = &quot;employee_type&quot;)
public class Employee {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private String name;

    // Getter, Setter, Constructor
}

@Entity
@DiscriminatorValue(&quot;MGR&quot;)
public class Manager extends Employee {
    private String department;

    // Getter, Setter, Constructor
}

@Entity
@DiscriminatorValue(&quot;ENG&quot;)
public class Engineer extends Employee {
    private String specialty;

    // Getter, Setter, Constructor
}&lt;/code&gt;&lt;/pre&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;JOINED 전략&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;각 엔티티를 별도의 테이블에 저장하고, 기본 키를 사용하여 상속 계층 구조를 연결하는 전략이다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;예시&lt;/h4&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1717029320398&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@Entity
@Inheritance(strategy = InheritanceType.JOINED)
public class Employee {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private String name;

    // Getter, Setter, Constructor
}

@Entity
public class Manager extends Employee {
    private String department;

    // Getter, Setter, Constructor
}

@Entity
public class Engineer extends Employee {
    private String specialty;

    // Getter, Setter, Constructor
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;TABLE_PER_CLASS 전략&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;각 엔티티를 별도의 테이블에 저장하고, 각 테이블이 상속된 모든 속성을 가지는 전략이다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;예시&lt;/h4&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1717029359638&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@Entity
@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
public class Employee {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;

    private String name;

    // Getter, Setter, Constructor
}

@Entity
public class Manager extends Employee {
    private String department;

    // Getter, Setter, Constructor
}

@Entity
public class Engineer extends Employee {
    private String specialty;

    // Getter, Setter, Constructor
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;데이터 저장, 수정, 삭제 예시&lt;/b&gt;&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1717029387783&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public void saveEmployeeAndManager(EntityManager em) {
    em.getTransaction().begin();

    Employee employee = new Employee();
    employee.setName(&quot;John Smith&quot;);

    Manager manager = new Manager();
    manager.setName(&quot;Jane Doe&quot;);
    manager.setDepartment(&quot;HR&quot;);

    em.persist(employee);
    em.persist(manager);
    em.getTransaction().commit();
}

public void updateManagerDepartment(EntityManager em, Long managerId) {
    em.getTransaction().begin();
    Manager manager = em.find(Manager.class, managerId);
    if (manager != null) {
        manager.setDepartment(&quot;Finance&quot;);
    }
    em.getTransaction().commit();
}

public void deleteEmployee(EntityManager em, Long employeeId) {
    em.getTransaction().begin();
    Employee employee = em.find(Employee.class, employeeId);
    if (employee != null) {
        em.remove(employee);
    }
    em.getTransaction().commit();
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;결론&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;JPA는 엔티티 간의 다양한 관계를 정의하고 관리할 수 있는 강력한 기능을 제공한다. &lt;b&gt;@OneToMany, @ManyToOne, @OneToOne, @ManyToMany&lt;/b&gt;를 통해 데이터베이스 모델을 객체 지향적으로 표현할 수 있다. 또한, &lt;b&gt;상속 매핑 전략(SINGLE_TABLE, JOINED, TABLE_PER_CLASS)&lt;/b&gt;을 통해 엔티티 간의 상속 관계를 효과적으로 구현할 수 있다.&amp;nbsp;&lt;/p&gt;</description>
      <category>Back-End</category>
      <author>h_jinnny</author>
      <guid isPermaLink="true">https://james-coding-study.tistory.com/74</guid>
      <comments>https://james-coding-study.tistory.com/74#entry74comment</comments>
      <pubDate>Thu, 30 May 2024 09:38:29 +0900</pubDate>
    </item>
    <item>
      <title>로깅(SLF4J)</title>
      <link>https://james-coding-study.tistory.com/73</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;소프트웨어 개발에서 로깅은 디버깅과 모니터링에 필수적인 요소이다. 자바 환경에서는 다양한 로깅 프레임워크가 존재하지만, 이러한 프레임워크를 통합적으로 관리하기 위해 &lt;b&gt;SLF4J(Simple Logging Facade for Java)&lt;/b&gt;가 등장했다. 이 글에서는 SLF4J의 개념, 장점, 사용법, 그리고 실제 코드 예제를 통해 SLF4J에 대해 알아보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;SLF4J란?&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;SLF4J는 자바에서 다양한 로깅 프레임워크에 대한 추상화된 인터페이스를 제공하는 통합 로깅 API이다. SLF4J는 로깅 프레임워크의 구현체에 의존하지 않고, 애플리케이션 코드에서 일관된 로깅 인터페이스를 사용할 수 있게 해준다. 대표적인 로깅 프레임워크로는 Logback, Log4j, Java Util Logging 등이 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&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;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;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;SLF4J의 장점&lt;/b&gt;&lt;/p&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;: SLF4J를 사용하면 로깅 프레임워크를 교체할 때 애플리케이션 코드를 수정할 필요 없이 설정만 변경하면 된다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;일관된 API 사용&lt;/b&gt;: 다양한 로깅 프레임워크의 API 차이를 신경쓰지 않고, SLF4J의 일관된 API를 사용할 수 있다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;성능 개선&lt;/b&gt;: SLF4J는 로깅 메시지의 생성을 지연시켜 성능을 최적화할 수 있다.&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;SLF4J 사용법&lt;/b&gt;&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;- Maven을 사용하여 SLF4J와 Logback을 프로젝트에 추가하는 방법은 다음과 같다:&lt;/p&gt;
&lt;pre id=&quot;code_1717006163796&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;dependency&amp;gt;
    &amp;lt;groupId&amp;gt;org.slf4j&amp;lt;/groupId&amp;gt;
    &amp;lt;artifactId&amp;gt;slf4j-api&amp;lt;/artifactId&amp;gt;
    &amp;lt;version&amp;gt;1.7.30&amp;lt;/version&amp;gt;
&amp;lt;/dependency&amp;gt;
&amp;lt;dependency&amp;gt;
    &amp;lt;groupId&amp;gt;ch.qos.logback&amp;lt;/groupId&amp;gt;
    &amp;lt;artifactId&amp;gt;logback-classic&amp;lt;/artifactId&amp;gt;
    &amp;lt;version&amp;gt;1.2.3&amp;lt;/version&amp;gt;
&amp;lt;/dependency&amp;gt;&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;- Gradle을 사용하는 경우:&lt;/p&gt;
&lt;pre id=&quot;code_1717006192412&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;implementation 'org.slf4j:slf4j-api:1.7.30'
implementation 'ch.qos.logback:logback-classic:1.2.3'&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;size18&quot;&gt;&lt;b&gt;로거 생성&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;SLF4J를 사용하여 로거를 생성하는 방법은 다음과 같다:&lt;/p&gt;
&lt;pre id=&quot;code_1717006218790&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class LoggingExample {
    private static final Logger logger = LoggerFactory.getLogger(LoggingExample.class);

    public static void main(String[] args) {
        logger.info(&quot;This is an info message&quot;);
        logger.debug(&quot;This is a debug message&quot;);
        logger.error(&quot;This is an error message&quot;);

        int value = 42;
        logger.info(&quot;The value is {}&quot;, value);
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;로깅 레벨&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;SLF4J는 여러 로깅 레벨을 제공한다. 주요 로깅 레벨은 다음과 같다:&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;TRACE&lt;/b&gt;: 가장 상세한 로깅 레벨로, 주로 개발 및 디버깅 목적으로 사용된다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;DEBUG&lt;/b&gt;: 디버깅 정보를 제공하며, 개발 중에 유용하다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;INFO&lt;/b&gt;: 일반적인 정보를 제공하며, 애플리케이션의 정상 동작을 알리는 메시지를 기록한다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;WARN&lt;/b&gt;: 경고를 의미하며, 잠재적인 문제를 기록한다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;ERROR&lt;/b&gt;: 오류를 의미하며, 애플리케이션의 문제를 기록한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;지연 로깅&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;SLF4J는 문자열 연산의 비용을 줄이기 위해 지연 로깅을 지원한다. 아래 예제는 문자열 연결 연산을 피하는 방법을 보여준다:&lt;/p&gt;
&lt;pre id=&quot;code_1717006250143&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;int value = 42;
logger.debug(&quot;The value is {}&quot;, value);&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;size18&quot;&gt;&lt;b&gt;SLF4J와 Logback 설정&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;SLF4J는 기본적으로 Logback을 사용하여 로깅을 처리한다. Logback의 설정 파일인 logback.xml을 통해 로깅 설정을 변경할 수 있다.&lt;/p&gt;
&lt;pre id=&quot;code_1717006303142&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&amp;gt;
&amp;lt;configuration&amp;gt;

    &amp;lt;appender name=&quot;STDOUT&quot; class=&quot;ch.qos.logback.core.ConsoleAppender&quot;&amp;gt;
        &amp;lt;encoder&amp;gt;
            &amp;lt;pattern&amp;gt;%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n&amp;lt;/pattern&amp;gt;
        &amp;lt;/encoder&amp;gt;
    &amp;lt;/appender&amp;gt;

    &amp;lt;root level=&quot;debug&quot;&amp;gt;
        &amp;lt;appender-ref ref=&quot;STDOUT&quot; /&amp;gt;
    &amp;lt;/root&amp;gt;

&amp;lt;/configuration&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&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;span&gt;SLF4J&lt;/span&gt;는&lt;span&gt; &lt;/span&gt;자바&lt;span&gt; &lt;/span&gt;애플리케이션에서&lt;span&gt; &lt;/span&gt;다양한&lt;span&gt; &lt;/span&gt;로깅&lt;span&gt; &lt;/span&gt;프레임워크를&lt;span&gt; &lt;/span&gt;통합적으로&lt;span&gt; &lt;/span&gt;관리할&lt;span&gt; &lt;/span&gt;수&lt;span&gt; &lt;/span&gt;있게&lt;span&gt; &lt;/span&gt;해주는&lt;span&gt; &lt;/span&gt;유용한&lt;span&gt; &lt;/span&gt;라이브러리이다&lt;span&gt;. SLF4J&lt;/span&gt;를&lt;span&gt; &lt;/span&gt;사용하면&lt;span&gt; &lt;/span&gt;로깅&lt;span&gt; &lt;/span&gt;프레임워크를&lt;span&gt; &lt;/span&gt;쉽게&lt;span&gt; &lt;/span&gt;교체할&lt;span&gt; &lt;/span&gt;수&lt;span&gt; &lt;/span&gt;있고&lt;span&gt;, &lt;/span&gt;일관된&lt;span&gt; API&lt;/span&gt;를&lt;span&gt; &lt;/span&gt;통해&lt;span&gt; &lt;/span&gt;로깅을&lt;span&gt; &lt;/span&gt;처리할&lt;span&gt; &lt;/span&gt;수&lt;span&gt; &lt;/span&gt;있다&lt;span&gt;. &lt;/span&gt;또한&lt;span&gt; &lt;/span&gt;성능&lt;span&gt; &lt;/span&gt;최적화를&lt;span&gt; &lt;/span&gt;위한&lt;span&gt; &lt;/span&gt;지연&lt;span&gt; &lt;/span&gt;로깅&lt;span&gt; &lt;/span&gt;기능도&lt;span&gt; &lt;/span&gt;제공한다&lt;span&gt;. SLF4J&lt;/span&gt;와&lt;span&gt; &lt;/span&gt;함께&lt;span&gt; Logback&lt;/span&gt;을&lt;span&gt; &lt;/span&gt;사용하여&lt;span&gt; &lt;/span&gt;강력하고&lt;span&gt; &lt;/span&gt;유연한&lt;span&gt; &lt;/span&gt;로깅&lt;span&gt; &lt;/span&gt;설정을&lt;span&gt; &lt;/span&gt;구성할 수 있다.&lt;/p&gt;</description>
      <category>Back-End</category>
      <author>h_jinnny</author>
      <guid isPermaLink="true">https://james-coding-study.tistory.com/73</guid>
      <comments>https://james-coding-study.tistory.com/73#entry73comment</comments>
      <pubDate>Thu, 30 May 2024 03:13:10 +0900</pubDate>
    </item>
    <item>
      <title>JPA와 ORM</title>
      <link>https://james-coding-study.tistory.com/72</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Java Persistence API (JPA)&lt;/b&gt;는 자바 플랫폼에서 &lt;b&gt;객체 관계 매핑(ORM)&lt;/b&gt; 기술을 위한 표준이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;ORM(Object-Relational Mapping)&lt;/b&gt;은 객체 지향 프로그래밍 언어의 객체를 관계형 데이터베이스의 테이블과 매핑하는 기술이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 글에서는 JPA의 핵심 요소인&lt;b&gt; EntityManagerFactory, EntityManager, persist&lt;/b&gt;&amp;nbsp;등에 대해 상세히 알아보고, JPA 구현체 중 하나인 &lt;b&gt;Hibernate&lt;/b&gt;에 대해서도 설명할 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;ORM과 Hibernate&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;ORM (Object-Relational Mapping)&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ORM은 객체 지향 프로그래밍 언어의 객체와 관계형 데이터베이스의 테이블 사이의 변환을 자동화하는 기술이다. ORM을 사용하면 SQL 쿼리를 직접 작성하지 않고도 데이터베이스와 상호작용할 수 있다. ORM의 주요 장점은 다음과 같다:&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;유지보수 용이&lt;/b&gt;: 코드가 간결해지고, 데이터베이스 스키마 변화에 유연하게 대응할 수 있다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;객체 지향적 프로그래밍&lt;/b&gt;: 객체 지향 패러다임에 맞는 코드를 작성할 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;Hibernate&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Hibernate는 JPA의 가장 널리 사용되는 구현체 중 하나로, 강력하고 유연한 ORM 프레임워크이다. Hibernate는 JPA 표준을 구현하며, 추가적인 기능을 제공한다. Hibernate를 사용하면 JPA의 장점을 활용하면서도 다양한 확장 기능을 사용할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;JPA의 주요 요소&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;EntityManagerFactory와 EntityManager&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;JPA에서 데이터베이스와의 상호작용을 관리하는 주요 인터페이스는 EntityManagerFactory와 EntityManager이다.&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;EntityManagerFactory&lt;/b&gt;: JPA 애플리케이션에서 데이터베이스와의 연결을 관리하는 팩토리 클래스이다. EntityManagerFactory는 애플리케이션 전체에서 하나만 생성되며, 여러 EntityManager 인스턴스를 생성하는 데 사용된다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;EntityManager&lt;/b&gt;: 실제 데이터베이스 작업을 수행하는 인터페이스이다. 데이터베이스 CRUD(Create, Read, Update, Delete) 작업을 관리하며, 엔티티의 생명주기를 관리한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;EntityManager와 EntityManagerFactory 예제&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음은 EntityManagerFactory와 EntityManager를 사용하는 예제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;JPADemo.java&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1717005627366&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import jakarta.persistence.EntityManager;
import jakarta.persistence.EntityManagerFactory;
import jakarta.persistence.Persistence;

public class JPADemo {
    public static void main(String[] args) {
        // EntityManagerFactory 생성
        EntityManagerFactory emf = Persistence.createEntityManagerFactory(&quot;my-persistence-unit&quot;);

        // EntityManager 생성
        EntityManager em = emf.createEntityManager();

        // 트랜잭션 시작
        em.getTransaction().begin();

        // 새로운 엔티티 생성 및 저장
        Person person = new Person();
        person.setName(&quot;John Doe&quot;);
        em.persist(person);

        // 트랜잭션 커밋
        em.getTransaction().commit();

        // EntityManager 종료
        em.close();

        // EntityManagerFactory 종료
        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;size18&quot;&gt;&lt;b&gt;Person.java&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1717005681631&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;

@Entity
public class Person {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private String name;

    // Getters and setters
    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;size18&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;Persistence.createEntityManagerFactory(&quot;my-persistence-unit&quot;): persistence.xml 파일에서 정의한 my-persistence-unit 이름의 영속성 유닛을 기반으로 EntityManagerFactory를 생성하는 코드이다.&lt;/li&gt;
&lt;li&gt;emf.createEntityManager(): EntityManagerFactory를 사용하여 EntityManager를 생성하는 코드이다.&lt;/li&gt;
&lt;li&gt;em.getTransaction().begin(): 트랜잭션을 시작하는 코드이다.&lt;/li&gt;
&lt;li&gt;em.persist(person): 새로운 엔티티를 데이터베이스에 저장하는 코드이다.&lt;/li&gt;
&lt;li&gt;em.getTransaction().commit(): 트랜잭션을 커밋하여 변경사항을 데이터베이스에 반영하는 코드이다.&lt;/li&gt;
&lt;li&gt;em.close(): EntityManager를 닫는 코드이다.&lt;/li&gt;
&lt;li&gt;emf.close(): EntityManagerFactory를 닫는 코드이다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;JPA의 주요 메서드&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;persist&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;persist 메서드는 새로운 엔티티를 영속성 컨텍스트에 저장한다. 엔티티가 영속성 컨텍스트에 저장되면, 트랜잭션이 커밋될 때 데이터베이스에 반영된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;find&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;find 메서드는 데이터베이스에서 엔티티를 조회한다.&lt;/p&gt;
&lt;pre id=&quot;code_1717005731421&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Person foundPerson = em.find(Person.class, personId);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;remove&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;remove 메서드는 영속성 컨텍스트에서 엔티티를 삭제한다.&lt;/p&gt;
&lt;pre id=&quot;code_1717005751465&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;em.remove(person);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;merge&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;merge 메서드는 분리된(Detached) 엔티티를 영속성 컨텍스트에 병합한다.&lt;/p&gt;
&lt;pre id=&quot;code_1717005767682&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Person mergedPerson = em.merge(detachedPerson);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;결론&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;JPA와 Hibernate는 자바 애플리케이션에서 데이터베이스와의 상호작용을 단순화하고, 생산성을 향상시키는 강력한 도구이다. EntityManagerFactory와 EntityManager는 JPA의 핵심 요소로, 데이터베이스 연결을 관리하고 CRUD 작업을 수행한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;persist, find, remove, merge와 같은 주요 메서드를 사용하여 엔티티의 생명주기를 관리할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;Hibernate&lt;/span&gt;는&lt;span&gt; JPA&lt;/span&gt;의&lt;span&gt; &lt;/span&gt;표준&lt;span&gt; &lt;/span&gt;구현체로&lt;span&gt;, &lt;/span&gt;추가적인&lt;span&gt; &lt;/span&gt;기능과&lt;span&gt; &lt;/span&gt;유연성을&lt;span&gt; &lt;/span&gt;제공하여&lt;span&gt; &lt;/span&gt;더욱&lt;span&gt; &lt;/span&gt;강력한&lt;span&gt; &lt;/span&gt;데이터베이스&lt;span&gt; &lt;/span&gt;관리를&lt;span&gt; &lt;/span&gt;가능하게&lt;span&gt; &lt;/span&gt;한다&lt;span&gt;.&lt;/span&gt;&lt;/p&gt;</description>
      <category>Back-End</category>
      <author>h_jinnny</author>
      <guid isPermaLink="true">https://james-coding-study.tistory.com/72</guid>
      <comments>https://james-coding-study.tistory.com/72#entry72comment</comments>
      <pubDate>Thu, 30 May 2024 03:03:56 +0900</pubDate>
    </item>
    <item>
      <title>JPA 기초 개념과 코드 예제 (Spring JPA 아님!!)</title>
      <link>https://james-coding-study.tistory.com/71</link>
      <description>&lt;div data-message-id=&quot;0c9dcb9c-17f3-4ba3-83b3-1fbea0d0c8e1&quot; data-message-author-role=&quot;assistant&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;JPA(Java Persistence API)는 자바에서 관계형 데이터베이스를 다루기 위한 표준 API이다. JPA를 사용하면 객체 지향적인 방식으로 데이터베이스 작업을 처리할 수 있다. JPA의 주요 개념과 이를 활용한 코드 예제를 작성하겠다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;엔티티(Entity)&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;엔티티(Entity)는 데이터베이스 테이블과 매핑되는 클래스이다. JPA를 사용하면 데이터베이스의 테이블을 객체 지향적으로 표현할 수 있다. 엔티티 클래스는 @Entity 어노테이션을 사용하여 정의하며, 각 필드는 데이터베이스 테이블의 컬럼에 매핑된다.&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1716856604827&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import jakarta.persistence.Entity;
import jakarta.persistence.Id;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Table;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;

@Entity
@Table(name = &quot;jpa_user&quot;)
@NoArgsConstructor
@Getter
@Setter
public class User {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String name;
    private String email;

    public User(String name, String email) {
        this.name = name;
        this.email = email;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 코드에서 User 클래스는 jpa_user 테이블과 매핑되며, id, name, email 필드는 각각 테이블의 컬럼에 매핑된다. @GeneratedValue 어노테이션은 id 필드가 자동으로 생성되는 값임을 나타낸다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;엔티티매니저팩토리(EntityManagerFactory)&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;엔티티매니저팩토리(EntityManagerFactory)는 JPA에서 엔티티매니저(EntityManager)를 생성하는 역할을 한다. 애플리케이션 전체에서 하나만 생성되어야 하며, 생성 비용이 크기 때문에 보통 애플리케이션이 시작될 때 한 번만 생성하고 공유한다.&lt;/p&gt;
&lt;pre id=&quot;code_1716856630603&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import jakarta.persistence.EntityManagerFactory;
import jakarta.persistence.Persistence;

public class JpaExample {
    public static void main(String[] args) {
        EntityManagerFactory emf = Persistence.createEntityManagerFactory(&quot;UserPU&quot;);
        // 엔티티매니저팩토리 생성
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;엔티티매니저(EntityManager)&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;엔티티매니저(EntityManager)는 엔티티를 관리하는 주요 객체이다. 엔티티의 생명주기를 관리하며, 데이터베이스 작업을 처리한다. 엔티티매니저를 통해 데이터베이스 트랜잭션을 시작, 커밋, 롤백할 수 있다. 엔티티매니저는 엔티티매니저팩토리에서 생성된다.&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1716856653147&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import jakarta.persistence.EntityManager;
import jakarta.persistence.EntityManagerFactory;
import jakarta.persistence.Persistence;

public class JpaExample {
    public static void main(String[] args) {
        EntityManagerFactory emf = Persistence.createEntityManagerFactory(&quot;UserPU&quot;);
        EntityManager em = emf.createEntityManager(); // 엔티티매니저 생성

        em.getTransaction().begin(); // 트랜잭션 시작

        User user = new User(&quot;John Doe&quot;, &quot;john@example.com&quot;);
        em.persist(user); // 엔티티 저장

        em.getTransaction().commit(); // 트랜잭션 커밋

        em.close(); // 엔티티매니저 종료
        emf.close(); // 엔티티매니저팩토리 종료
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;영속성 컨텍스트(Persistence Context)&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;영속성 컨텍스트(Persistence Context)는 엔티티를 영구 저장소에 저장하는 환경을 의미한다. 엔티티매니저는 영속성 컨텍스트를 통해 엔티티를 관리한다. 영속성 컨텍스트는 엔티티의 상태를 관리하며, 동일한 영속성 컨텍스트 내에서는 동일한 엔티티가 공유된다. 이를 통해 1차 캐시 기능을 제공하여 성능을 최적화한다.&lt;/p&gt;
&lt;pre id=&quot;code_1716856700750&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import jakarta.persistence.EntityManager;
import jakarta.persistence.EntityManagerFactory;
import jakarta.persistence.Persistence;

public class JpaExample {
    public static void main(String[] args) {
        EntityManagerFactory emf = Persistence.createEntityManagerFactory(&quot;UserPU&quot;);
        EntityManager em = emf.createEntityManager(); // 엔티티매니저 생성

        em.getTransaction().begin(); // 트랜잭션 시작

        User user = new User(&quot;John Doe&quot;, &quot;john@example.com&quot;);
        em.persist(user); // 엔티티 저장 (영속 상태)

        User foundUser = em.find(User.class, user.getId()); // 영속성 컨텍스트에서 조회
        System.out.println(foundUser.getName()); // &quot;John Doe&quot;

        em.getTransaction().commit(); // 트랜잭션 커밋

        em.close(); // 엔티티매니저 종료
        emf.close(); // 엔티티매니저팩토리 종료
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;META-INF&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;META-INF는 JAR 파일의 메타데이터를 저장하는 디렉토리이다. JPA 설정 파일인 persistence.xml은 이 디렉토리에 위치해야 한다. persistence.xml 파일은 영속성 유닛을 정의하고, 데이터베이스 연결 설정, JPA 구현체, 엔티티 클래스를 설정한다.&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1716856900143&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;META-INF/
    persistence.xml&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;persistence.xml&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;persistence.xml은 JPA 설정 파일로, 영속성 유닛(Persistence Unit)을 정의한다. 이 파일은 META-INF 디렉토리에 위치하며, 데이터베이스 연결 정보와 JPA 구현체를 설정한다.&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1716856935380&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&amp;gt;
&amp;lt;persistence xmlns=&quot;http://java.sun.com/xml/ns/persistence&quot;
             xmlns:xsi=&quot;http://www.w3.org/2001/XMLSchema-instance&quot;
             xsi:schemaLocation=&quot;http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd&quot;
             version=&quot;2.0&quot;&amp;gt;

    &amp;lt;persistence-unit name=&quot;UserPU&quot; transaction-type=&quot;RESOURCE_LOCAL&quot;&amp;gt;
        &amp;lt;provider&amp;gt;org.hibernate.jpa.HibernatePersistenceProvider&amp;lt;/provider&amp;gt;
        &amp;lt;class&amp;gt;com.example.jpa.User&amp;lt;/class&amp;gt;  &amp;lt;!-- Add this line --&amp;gt;
        &amp;lt;properties&amp;gt;
            &amp;lt;property name=&quot;jakarta.persistence.jdbc.driver&quot; value=&quot;com.mysql.cj.jdbc.Driver&quot;/&amp;gt;
            &amp;lt;property name=&quot;jakarta.persistence.jdbc.url&quot; value=&quot;jdbc:mysql://localhost:3307/exam&quot;/&amp;gt;
            &amp;lt;property name=&quot;jakarta.persistence.jdbc.user&quot; value=&quot;jeon&quot;/&amp;gt;
            &amp;lt;property name=&quot;jakarta.persistence.jdbc.password&quot; value=&quot;1234&quot;/&amp;gt;

            &amp;lt;!--create, update, create-drop, validate, none 중에 하나를 지정할 수 있음--&amp;gt;
            &amp;lt;property name=&quot;hibernate.hbm2ddl.auto&quot; value=&quot;update&quot;/&amp;gt;

            &amp;lt;!--사용할 데이터베이스 방언을 지정한다--&amp;gt;
            &amp;lt;property name=&quot;hibernate.dialect&quot; value=&quot;org.hibernate.dialect.MySQLDialect&quot;/&amp;gt;

            &amp;lt;!--: SQL 명령어를 콘솔에 출력하고 포맷팅할지 여부를 설정한다--&amp;gt;
            &amp;lt;property name=&quot;hibernate.show_sql&quot; value=&quot;true&quot;/&amp;gt;
            &amp;lt;property name=&quot;hibernate.format_sql&quot; value=&quot;true&quot;/&amp;gt;
        &amp;lt;/properties&amp;gt;
    &amp;lt;/persistence-unit&amp;gt;
&amp;lt;/persistence&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&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;하이버네이트(Hibernate)&lt;/b&gt;&lt;/h2&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;하이버네이트(Hibernate)는 JPA의 구현체 중 하나로, ORM(Object-Relational Mapping) 프레임워크이다. JPA 표준을 구현하고 있으며, 데이터베이스와 객체 지향 프로그래밍 간의 불일치를 해결해준다. 하이버네이트를 사용하면 SQL 쿼리를 작성하지 않고도 데이터베이스 작업을 객체 지향적으로 수행할 수 있다.&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;JPA는 객체와 관계형 데이터베이스 간의 매핑을 간단하게 처리할 수 있도록 도와주는 강력한 프레임워크이다. 이를 통해 개발자는 객체 지향 프로그래밍 패러다임을 유지하면서도 데이터베이스 작업을 효율적으로 수행할 수 있다.&lt;/p&gt;
&lt;/div&gt;</description>
      <category>Back-End/Spring</category>
      <author>h_jinnny</author>
      <guid isPermaLink="true">https://james-coding-study.tistory.com/71</guid>
      <comments>https://james-coding-study.tistory.com/71#entry71comment</comments>
      <pubDate>Tue, 28 May 2024 09:46:01 +0900</pubDate>
    </item>
    <item>
      <title>Spring MVC의 @RequestParam과 @PathVariable 사용법</title>
      <link>https://james-coding-study.tistory.com/70</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;Spring MVC는 웹 애플리케이션을 쉽게 만들 수 있는 다양한 어노테이션을 제공하는 프레임워크이다. 이 중 @RequestParam과 @PathVariable은 URL로부터 파라미터를 추출하는 데 사용된다. 이 글에서는 이 두 어노테이션의 차이점과 사용법을 자세히 살펴보겠다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;@RequestParam&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;@RequestParam 어노테이션은 HTTP 요청의 파라미터를 메서드의 파라미터로 바인딩하는 데 사용된다. GET 요청이나 POST 요청에서 쿼리 스트링 또는 폼 데이터를 쉽게 처리할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;예제 1: 기본 사용법&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1716425860387&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;

@Controller
public class RequestParamController {

    @GetMapping(&quot;/greeting&quot;)
    public String greeting(@RequestParam(name = &quot;name&quot;, required = false, defaultValue = &quot;World&quot;) String name, Model model) {
        model.addAttribute(&quot;name&quot;, name);
        return &quot;greeting&quot;;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&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;@RequestParam(name = &quot;name&quot;, required = false, defaultValue = &quot;World&quot;)는 URL 쿼리 파라미터 name을 메서드 파라미터 name에 바인딩하는 것이다.&lt;/li&gt;
&lt;li&gt;required가 false로 설정되어 있어 name 파라미터가 없어도 에러가 발생하지 않는다. defaultValue는 파라미터가 없을 때 사용할 기본값을 지정하는 것이다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size18&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;URL: http://localhost:8080/greeting?name=John&lt;/li&gt;
&lt;li&gt;URL: http://localhost:8080/greeting&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;@PathVariable&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;@PathVariable 어노테이션은 URL 경로에 있는 값을 메서드의 파라미터로 바인딩하는 데 사용된다. RESTful 웹 서비스에서 자주 사용된다.&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;예제 2: 기본 사용법&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1716425897057&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.ResponseBody;

@Controller
public class PathVariableController {

    @GetMapping(&quot;/user/{userId}&quot;)
    @ResponseBody
    public String getUser(@PathVariable(&quot;userId&quot;) String userId) {
        return &quot;User ID: &quot; + userId;
    }
}&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;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;@PathVariable(&quot;userId&quot;)는 URL 경로에서 {userId} 부분을 메서드 파라미터 userId에 바인딩하는 것이다.&lt;/li&gt;
&lt;li&gt;@ResponseBody는 반환 값을 HTTP 응답 본문으로 직접 보내는 데 사용된다.&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;URL: http://localhost:8080/user/123&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;@RequestParam과 @PathVariable의 차이점&lt;/b&gt;&lt;/h4&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;: @RequestParam은 쿼리 스트링 또는 폼 데이터에서 값을 가져오고, @PathVariable은 URL 경로에서 값을 가져오는 것이다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;용도&lt;/b&gt;: @RequestParam은 주로 필터링, 검색, 페이징 등에 사용되며, @PathVariable은 RESTful 서비스에서 리소스를 식별하는 데 사용된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt; 두 어노테이션을 같이 사용하는 예제&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&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;예제 3: 복합 사용&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1716425955230&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestParam;

@Controller
public class CombinedController {

    @GetMapping(&quot;/products/{productId}&quot;)
    public String getProduct(@PathVariable(&quot;productId&quot;) String productId, @RequestParam(name = &quot;category&quot;, required = false) String category, Model model) {
        model.addAttribute(&quot;productId&quot;, productId);
        model.addAttribute(&quot;category&quot;, category);
        return &quot;product&quot;;
    }
}&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;product.html&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1716425972396&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;!DOCTYPE html&amp;gt;
&amp;lt;html xmlns:th=&quot;http://www.thymeleaf.org&quot;&amp;gt;
&amp;lt;head&amp;gt;
    &amp;lt;title&amp;gt;Product&amp;lt;/title&amp;gt;
&amp;lt;/head&amp;gt;
&amp;lt;body&amp;gt;
&amp;lt;h1&amp;gt;Product Details&amp;lt;/h1&amp;gt;
&amp;lt;p&amp;gt;Product ID: &amp;lt;span th:text=&quot;${productId}&quot;&amp;gt;&amp;lt;/span&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;Category: &amp;lt;span th:text=&quot;${category}&quot;&amp;gt;&amp;lt;/span&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/body&amp;gt;
&amp;lt;/html&amp;gt;&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;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;@PathVariable(&quot;productId&quot;)는 URL 경로에서 {productId} 값을 추출하는 것이다.&lt;/li&gt;
&lt;li&gt;@RequestParam(name = &quot;category&quot;, required = false)는 쿼리 스트링에서 category 값을 추출하는 것이다.&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;URL: http://localhost:8080/products/456?category=Electronics&lt;/li&gt;
&lt;li&gt;URL: http://localhost:8080/products/456&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;결론&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Spring MVC&lt;span&gt;의&lt;/span&gt; @RequestParam&lt;span&gt;과&lt;/span&gt; @PathVariable &lt;span&gt;어노테이션은&lt;/span&gt; &lt;span&gt;웹&lt;/span&gt; &lt;span&gt;애플리케이션에서&lt;/span&gt; URL&lt;span&gt;로부터&lt;/span&gt; &lt;span&gt;파라미터를&lt;/span&gt; &lt;span&gt;추출하는&lt;/span&gt; &lt;span&gt;데&lt;/span&gt; &lt;span&gt;매우&lt;/span&gt; &lt;span&gt;유용하다&lt;/span&gt;. @RequestParam&lt;span&gt;은&lt;/span&gt; &lt;span&gt;쿼리&lt;/span&gt; &lt;span&gt;스트링&lt;/span&gt; &lt;span&gt;또는&lt;/span&gt; &lt;span&gt;폼&lt;/span&gt; &lt;span&gt;데이터를&lt;/span&gt; &lt;span&gt;처리하는&lt;/span&gt; &lt;span&gt;데&lt;/span&gt; &lt;span&gt;사용되고&lt;/span&gt;, @PathVariable&lt;span&gt;은&lt;/span&gt; URL &lt;span&gt;경로의&lt;/span&gt; &lt;span&gt;변수를&lt;/span&gt; &lt;span&gt;처리하는&lt;/span&gt; &lt;span&gt;데&lt;/span&gt; &lt;span&gt;사용된다&lt;/span&gt;. &lt;span&gt;이&lt;/span&gt; &lt;span&gt;두&lt;/span&gt; &lt;span&gt;어노테이션을&lt;/span&gt; &lt;span&gt;적절히&lt;/span&gt; &lt;span&gt;활용하면&lt;/span&gt; &lt;span&gt;더욱&lt;/span&gt; &lt;span&gt;유연하고&lt;/span&gt; &lt;span&gt;강력한&lt;/span&gt; &lt;span&gt;웹&lt;/span&gt; &lt;span&gt;애플리케이션을&lt;/span&gt; &lt;span&gt;개발할&lt;/span&gt; &lt;span&gt;수&lt;/span&gt; &lt;span&gt;있다&lt;/span&gt;.&lt;/p&gt;</description>
      <category>Back-End/Spring</category>
      <author>h_jinnny</author>
      <guid isPermaLink="true">https://james-coding-study.tistory.com/70</guid>
      <comments>https://james-coding-study.tistory.com/70#entry70comment</comments>
      <pubDate>Thu, 23 May 2024 10:00:47 +0900</pubDate>
    </item>
  </channel>
</rss>