<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>슬개</title>
    <link>https://doltae.tistory.com/</link>
    <description>슬개의 공부 블로그</description>
    <language>ko</language>
    <pubDate>Fri, 12 Jun 2026 20:29:36 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>슬기로운 개발자</managingEditor>
    <image>
      <title>슬개</title>
      <url>https://tistory1.daumcdn.net/tistory/5036081/attach/613ee9ee81cf4a4d8ca6bebce74dc728</url>
      <link>https://doltae.tistory.com</link>
    </image>
    <item>
      <title>문자열 불변 객체(Immutable)와 가변 객체(Mutable)의 차이점</title>
      <link>https://doltae.tistory.com/484</link>
      <description>&lt;h2 data-end=&quot;80&quot; data-start=&quot;44&quot; data-ke-size=&quot;size26&quot;&gt;1. String 불변객체 (Immutable Object)&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;165&quot; data-start=&quot;82&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;132&quot; data-start=&quot;82&quot;&gt;&lt;b&gt;불변(Immutable)&lt;/b&gt;: 한 번 생성된 객체의 상태(값)가 변경되지 않는 객체&lt;/li&gt;
&lt;li data-end=&quot;165&quot; data-start=&quot;133&quot;&gt;&lt;b&gt;Java String 클래스가 대표적인 불변객체&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-end=&quot;173&quot; data-start=&quot;167&quot; data-ke-size=&quot;size23&quot;&gt;특징&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;363&quot; data-start=&quot;174&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;223&quot; data-start=&quot;174&quot;&gt;String 객체는 한 번 생성되면 내부에 저장된 문자(char 배열)가 바뀌지 않음&lt;/li&gt;
&lt;li data-end=&quot;289&quot; data-start=&quot;224&quot;&gt;문자열을 변경하는 연산(예: concat, replace 등)을 하면 실제로는 새로운 String 객체가 만들어짐&lt;/li&gt;
&lt;li data-end=&quot;328&quot; data-start=&quot;290&quot;&gt;불변성 때문에 여러 스레드에서 안전하게 공유 가능(스레드 안정성)&lt;/li&gt;
&lt;li data-end=&quot;363&quot; data-start=&quot;329&quot;&gt;메모리 관리와 최적화에 유리 (String Pool 활용)&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-end=&quot;371&quot; data-start=&quot;365&quot; data-ke-size=&quot;size23&quot;&gt;예시&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1753864445152&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;String s1 = &quot;hello&quot;;
String s2 = s1.concat(&quot; world&quot;);  // 새로운 객체 생성, s1은 변경되지 않음&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;h2 data-end=&quot;505&quot; data-start=&quot;471&quot; data-ke-size=&quot;size26&quot;&gt;2. String 가변객체 (Mutable Object)&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;604&quot; data-start=&quot;507&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;552&quot; data-start=&quot;507&quot;&gt;&lt;b&gt;가변(Mutable)&lt;/b&gt;: 객체 생성 후 내부 상태를 변경할 수 있는 객체&lt;/li&gt;
&lt;li data-end=&quot;604&quot; data-start=&quot;553&quot;&gt;Java에서는 대표적으로 StringBuilder, StringBuffer가 있음&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-end=&quot;612&quot; data-start=&quot;606&quot; data-ke-size=&quot;size23&quot;&gt;특징&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;781&quot; data-start=&quot;613&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;654&quot; data-start=&quot;613&quot;&gt;문자열을 변경할 때 새로운 객체를 생성하지 않고 내부 버퍼를 직접 수정&lt;/li&gt;
&lt;li data-end=&quot;682&quot; data-start=&quot;655&quot;&gt;성능상 이점 (특히 문자열을 자주 수정할 때)&lt;/li&gt;
&lt;li data-end=&quot;736&quot; data-start=&quot;683&quot;&gt;StringBuffer는 동기화(Synchronized) 지원해서 멀티스레드 환경에 안전&lt;/li&gt;
&lt;li data-end=&quot;781&quot; data-start=&quot;737&quot;&gt;StringBuilder는 동기화 안 해서 단일 스레드 환경에서 더 빠름&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-end=&quot;789&quot; data-start=&quot;783&quot; data-ke-size=&quot;size23&quot;&gt;예시&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1753864430743&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;StringBuilder sb = new StringBuilder(&quot;hello&quot;);
sb.append(&quot; world&quot;);  // 기존 객체 내부가 변경됨&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-end=&quot;901&quot; data-start=&quot;894&quot; data-ke-size=&quot;size26&quot;&gt;요약 표&lt;/h2&gt;
&lt;div&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-end=&quot;1342&quot; data-start=&quot;903&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;구분&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;&lt;b&gt;불변 객체(Immutable)&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;&lt;b&gt;가변 객체(Mutable)&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;1136&quot; data-start=&quot;1059&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1071&quot; data-start=&quot;1059&quot;&gt;대표 클래스&lt;/td&gt;
&lt;td data-end=&quot;1101&quot; data-start=&quot;1071&quot; data-col-size=&quot;sm&quot;&gt;String&lt;/td&gt;
&lt;td data-end=&quot;1136&quot; data-start=&quot;1101&quot; data-col-size=&quot;sm&quot;&gt;StringBuilder, StringBuffer&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;1200&quot; data-start=&quot;1137&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1149&quot; data-start=&quot;1137&quot;&gt;상태 변경 시&lt;/td&gt;
&lt;td data-end=&quot;1173&quot; data-start=&quot;1149&quot; data-col-size=&quot;sm&quot;&gt;새로운 객체 생성&lt;/td&gt;
&lt;td data-end=&quot;1200&quot; data-start=&quot;1173&quot; data-col-size=&quot;sm&quot;&gt;기존 객체 내부 변경&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;1281&quot; data-start=&quot;1201&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1213&quot; data-start=&quot;1201&quot;&gt;멀티스레드 안정성&lt;/td&gt;
&lt;td data-end=&quot;1237&quot; data-start=&quot;1213&quot; data-col-size=&quot;sm&quot;&gt;기본적으로 안전&lt;/td&gt;
&lt;td data-end=&quot;1281&quot; data-start=&quot;1237&quot; data-col-size=&quot;sm&quot;&gt;StringBuffer는 안전, StringBuilder는 비안전&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;1342&quot; data-start=&quot;1282&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1296&quot; data-start=&quot;1282&quot;&gt;성능&lt;/td&gt;
&lt;td data-end=&quot;1318&quot; data-start=&quot;1296&quot; data-col-size=&quot;sm&quot;&gt;변경 많으면 비효율적&lt;/td&gt;
&lt;td data-end=&quot;1342&quot; data-start=&quot;1318&quot; data-col-size=&quot;sm&quot;&gt;문자열 변경 작업에 효율적&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-end=&quot;62&quot; data-start=&quot;26&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;String 불변객체와 힙(Heap) 영역 관련 핵심 정리&lt;/b&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;607&quot; data-start=&quot;64&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;157&quot; data-start=&quot;64&quot;&gt;&lt;b&gt;String 객체는 힙 영역에 저장된다.&lt;/b&gt;&lt;br /&gt;실제로 String 객체는 힙(heap) 영역에 생성되고, 내부에는 문자(char 배열)가 저장돼 있어.&lt;/li&gt;
&lt;li data-end=&quot;239&quot; data-start=&quot;159&quot;&gt;&lt;b&gt;불변객체라서 &amp;lsquo;내부 문자 배열&amp;rsquo;이 바뀌지 않는다.&lt;/b&gt;&lt;br /&gt;즉, 생성된 String 객체의 문자 배열은 바뀌지 않고 그대로 유지돼.&lt;/li&gt;
&lt;li data-end=&quot;421&quot; data-start=&quot;241&quot;&gt;&lt;b&gt;참조 변수는 힙에 있는 String 객체의 주소값(참조값)을 가진다.&lt;/b&gt;&lt;br /&gt;예를 들어,여기서 s는 스택(stack)에 저장된 참조 변수이고, 실제 문자열 &quot;hello&quot;는 힙 영역에 저장된 String 객체 내부에 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1753864531815&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;String s = &quot;hello&quot;;&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;607&quot; data-start=&quot;64&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;607&quot; data-start=&quot;423&quot;&gt;&lt;b&gt;새로운 문자열 연산이 일어나면 기존 문자열을 변경하는 게 아니라, 새로운 힙 영역에 다른 String 객체가 만들어지고 참조 변수가 새 객체를 가리킨다.&lt;/b&gt;이때는 새로운 String 객체가 힙에 생성되고, s는 새 객체를 참조하게 됨.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1753864537262&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;s = s + &quot; world&quot;;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-end=&quot;620&quot; data-start=&quot;614&quot; data-ke-size=&quot;size23&quot;&gt;핵심&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;705&quot; data-start=&quot;622&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;658&quot; data-start=&quot;622&quot;&gt;불변객체는 &lt;b&gt;기존 힙 영역의 값을 직접 변경하지 않고&lt;/b&gt;&lt;/li&gt;
&lt;li data-end=&quot;705&quot; data-start=&quot;659&quot;&gt;참조 변수는 힙 영역에 저장된 객체(문자열 데이터)의 주소를 가리키는 것 뿐임.&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>Back-End/Java</category>
      <author>슬기로운 개발자</author>
      <guid isPermaLink="true">https://doltae.tistory.com/484</guid>
      <comments>https://doltae.tistory.com/484#entry484comment</comments>
      <pubDate>Wed, 30 Jul 2025 17:38:45 +0900</pubDate>
    </item>
    <item>
      <title>스프링 배치 도메인 이해 - Job</title>
      <link>https://doltae.tistory.com/459</link>
      <description>&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;I. Job 기본 개념&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;middot;&lt;span&gt;&amp;nbsp; 배치 계층 구조의 가장 상위에 있는 개념, 하나의 배치 작업을 의미한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;- &quot;API 서버의 접속 로그 데이터를 통계 서버로 옮기는 배치&quot;, Job 자체를 의미&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;middot; Job Configuration을 통해 생성되는 객체 단위,&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;middot; Job을 구성하기 위한 최상위 인터페이스, 스프링 배치의 기본 구현체 제공.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;middot; 여러 Step을 포함하고 있는 컨테이너로서 반드시 한개 이상의 Step으로 구성해야함.&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;애플리케이션을 실행하는 데 필요한 모든 요소(코드, 라이브러리, 설정 파일 등)를 하나로 묶어 경량화된 실행 환경을 제공하는 기술&lt;/p&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;II. Job 기본 구현체&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt; &amp;middot; SimpleJob(Step을 포함)&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 순차적으로 Step을 실행시키는 Job&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 모든 Job에서 유용하게 사용할 수 있는 표준 기능을 갖고 있음.&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;&amp;middot; FlowJob(Step을 포함 + Flow 객체 포함)&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 특정한 조건과 흐름에 따라 Step을 구성하여 실행시키는 Job&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- Flow 객체를 실행시켜서 작업을 진행함.&lt;/p&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;III. Job 동작 원리&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;JobParameters -&amp;gt; JobLauncher &lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;-&amp;gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;b&gt;run(job, parameters)&lt;/b&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;Job -&amp;gt;&lt;b&gt; execute()&lt;/b&gt; -&amp;gt; Steps -&amp;gt; Step&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;uarr;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Job 실행메서드 Job void excute(JobExecution)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;uarr;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;AbstractJob&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;name : Job 이름&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;restartable : 재시작 여부 : 기본값은 true&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;JobRepository : 메타데이터 저장소&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;JobExecutionListener : Job 이벤트 리스너&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;JobParametersIncrementer : JobParameter 증가기&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;JobParametersValidator : JobParameter 검증기&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;SimpleStepHandler : Step 실행 핸들러&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;uarr;&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 43.6046%; height: 67px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 50%; text-align: center;&quot;&gt;&lt;b&gt;SimpleJob&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 50%; text-align: center;&quot;&gt;&lt;b&gt;FlowJob&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 50%; text-align: center;&quot;&gt;steps&lt;/td&gt;
&lt;td style=&quot;width: 50%; text-align: center;&quot;&gt;Flow&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&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 style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;@ Job 구조 디버깅 모드로 따라가보기.&lt;/b&gt;&lt;/span&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 style=&quot;color: #000000;&quot;&gt;JobConfiguration.java(잡 기본 구성 소스 작성)&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;crystal&quot;&gt;&lt;code&gt;package io.springbatch.springbatchseulgae;

import lombok.RequiredArgsConstructor;
import org.springframework.batch.core.Job;
import org.springframework.batch.core.Step;
import org.springframework.batch.core.StepContribution;
import org.springframework.batch.core.configuration.annotation.JobBuilderFactory;
import org.springframework.batch.core.configuration.annotation.StepBuilderFactory;
import org.springframework.batch.core.scope.context.ChunkContext;
import org.springframework.batch.core.step.tasklet.Tasklet;
import org.springframework.batch.repeat.RepeatStatus;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
@RequiredArgsConstructor
public class JobConfiguration {

    private final JobBuilderFactory jobBuilderFactory;
    private final StepBuilderFactory stepBuilderFactory;

    @Bean
    public Job job() {
        return jobBuilderFactory.get(&quot;job&quot;)
                .start(step1())
                .next(step2())
                .build();
    }

    @Bean
    public Step step1() {
        return stepBuilderFactory.get(&quot;step1&quot;)
                .tasklet(new Tasklet() {
                    @Override
                    public RepeatStatus execute(StepContribution stepContribution, ChunkContext chunkContext) throws Exception {
                        System.out.println(&quot;step1 was executed&quot;);
                        return RepeatStatus.FINISHED;
                    }
                })
                .build();
    }

    @Bean
    public Step step2() {
        return stepBuilderFactory.get(&quot;step2&quot;)
                .tasklet(new Tasklet() {
                    @Override
                    public RepeatStatus execute(StepContribution stepContribution, ChunkContext chunkContext) throws Exception {
                        System.out.println(&quot;step2 was executed&quot;);
                        return RepeatStatus.FINISHED;
                    }
                })
                .build();
    }

}
&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;작성한 Job 메서드를 기준으로 디버깅 모드해서 따라가면&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;635&quot; data-origin-height=&quot;177&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/3JUe0/btsNtpSo0qS/CIpaMf2nc07TKEfKF2fFkK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/3JUe0/btsNtpSo0qS/CIpaMf2nc07TKEfKF2fFkK/img.png&quot; data-alt=&quot;Job 메서드&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/3JUe0/btsNtpSo0qS/CIpaMf2nc07TKEfKF2fFkK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F3JUe0%2FbtsNtpSo0qS%2FCIpaMf2nc07TKEfKF2fFkK%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;635&quot; height=&quot;177&quot; data-origin-width=&quot;635&quot; data-origin-height=&quot;177&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;Job 메서드&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Job에 Ctrl + Alt + B 누르면 Choose Implementation of Job을 볼 수 있음.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1236&quot; data-origin-height=&quot;221&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Pfz2z/btsNrrJzllo/BZvpLAxVsqw3scPpAMYZD0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Pfz2z/btsNrrJzllo/BZvpLAxVsqw3scPpAMYZD0/img.png&quot; data-alt=&quot;Job의 구현 메서드&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Pfz2z/btsNrrJzllo/BZvpLAxVsqw3scPpAMYZD0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FPfz2z%2FbtsNrrJzllo%2FBZvpLAxVsqw3scPpAMYZD0%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;1236&quot; height=&quot;221&quot; data-origin-width=&quot;1236&quot; data-origin-height=&quot;221&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;Job의 구현 메서드&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. JobBuilder 호출&lt;/p&gt;
&lt;div style=&quot;background-color: #1e1f22; color: #bcbec4;&quot;&gt;
&lt;pre class=&quot;arduino&quot;&gt;&lt;code&gt;//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//

package org.springframework.batch.core.job.builder;

import org.springframework.batch.core.Step;
import org.springframework.batch.core.job.flow.Flow;

public class JobBuilder extends JobBuilderHelper&amp;lt;JobBuilder&amp;gt; {
    public JobBuilder(String name) {
        super(name);
    }

    public SimpleJobBuilder start(Step step) {
        return (new SimpleJobBuilder(this)).start(step);
    }

    public JobFlowBuilder start(Flow flow) {
        return (new FlowJobBuilder(this)).start(flow);
    }

    public JobFlowBuilder flow(Step step) {
        return (new FlowJobBuilder(this)).start(step);
    }
}
&lt;/code&gt;&lt;/pre&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;2. 요안의&amp;nbsp; SimpleJobBuilder 클래스 호출한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;열어보면 SimpleJob이라는 객체를 생성하고, SimpleJobBuilder 클래스의 start 메서드를 호출하는데 구조를 살펴보면&lt;/p&gt;
&lt;div style=&quot;background-color: #1e1f22; color: #bcbec4;&quot;&gt;
&lt;pre class=&quot;kotlin&quot;&gt;&lt;code&gt;//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//

package org.springframework.batch.core.job.builder;

import java.util.ArrayList;
import java.util.List;
import org.springframework.batch.core.Job;
import org.springframework.batch.core.Step;
import org.springframework.batch.core.job.SimpleJob;
import org.springframework.batch.core.job.flow.JobExecutionDecider;
import org.springframework.core.task.TaskExecutor;
import org.springframework.util.Assert;

public class SimpleJobBuilder extends JobBuilderHelper&amp;lt;SimpleJobBuilder&amp;gt; {
    private List&amp;lt;Step&amp;gt; steps = new ArrayList();
    private JobFlowBuilder builder;

    public SimpleJobBuilder(JobBuilderHelper&amp;lt;?&amp;gt; parent) {
        super(parent);
    }

    public Job build() {
        if (this.builder != null) {
            return ((FlowJobBuilder)this.builder.end()).build();
        } else {
            SimpleJob job = new SimpleJob(this.getName());
            super.enhance(job);
            job.setSteps(this.steps);

            try {
                job.afterPropertiesSet();
                return job;
            } catch (Exception e) {
                throw new JobBuilderException(e);
            }
        }
    }

    public SimpleJobBuilder start(Step step) {
        if (this.steps.isEmpty()) {
            this.steps.add(step);
        } else {
            this.steps.set(0, step);
        }

        return this;
    }

    public FlowBuilder.TransitionBuilder&amp;lt;FlowJobBuilder&amp;gt; on(String pattern) {
        Assert.state(this.steps.size() &amp;gt; 0, &quot;You have to start a job with a step&quot;);

        for(Step step : this.steps) {
            if (this.builder == null) {
                this.builder = new JobFlowBuilder(new FlowJobBuilder(this), step);
            } else {
                this.builder.next(step);
            }
        }

        return this.builder.on(pattern);
    }

    public JobFlowBuilder start(JobExecutionDecider decider) {
        if (this.builder == null) {
            this.builder = new JobFlowBuilder(new FlowJobBuilder(this), decider);
        } else {
            this.builder.start(decider);
        }

        if (!this.steps.isEmpty()) {
            this.steps.remove(0);
        }

        for(Step step : this.steps) {
            this.builder.next(step);
        }

        return this.builder;
    }

    public JobFlowBuilder next(JobExecutionDecider decider) {
        for(Step step : this.steps) {
            if (this.builder == null) {
                this.builder = new JobFlowBuilder(new FlowJobBuilder(this), step);
            } else {
                this.builder.next(step);
            }
        }

        if (this.builder == null) {
            this.builder = new JobFlowBuilder(new FlowJobBuilder(this), decider);
        } else {
            this.builder.next(decider);
        }

        return this.builder;
    }

    public SimpleJobBuilder next(Step step) {
        this.steps.add(step);
        return this;
    }

    public FlowBuilder.SplitBuilder&amp;lt;FlowJobBuilder&amp;gt; split(TaskExecutor executor) {
        for(Step step : this.steps) {
            if (this.builder == null) {
                this.builder = new JobFlowBuilder(new FlowJobBuilder(this), step);
            } else {
                this.builder.next(step);
            }
        }

        if (this.builder == null) {
            this.builder = new JobFlowBuilder(new FlowJobBuilder(this));
        }

        return this.builder.split(executor);
    }
}
&lt;/code&gt;&lt;/pre&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;3. Step을 저장할 리스트 변수가 선언되어있고&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;731&quot; data-origin-height=&quot;94&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bpFlxg/btsNsUr0Vwu/KCi4vWZCFcXbUvKVebnM5k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bpFlxg/btsNsUr0Vwu/KCi4vWZCFcXbUvKVebnM5k/img.png&quot; data-alt=&quot;Step을 저장하는 List 변수&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bpFlxg/btsNsUr0Vwu/KCi4vWZCFcXbUvKVebnM5k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbpFlxg%2FbtsNsUr0Vwu%2FKCi4vWZCFcXbUvKVebnM5k%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;731&quot; height=&quot;94&quot; data-origin-width=&quot;731&quot; data-origin-height=&quot;94&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;Step을 저장하는 List 변수&lt;/figcaption&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;4. 따라서 내려가다보면 Job build() 메서드가 보이는데 여기서 SimpleJob 객체를 생성한다.&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;564&quot; data-origin-height=&quot;361&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Ldx0i/btsNsEImCAQ/khbOd2EINQB09pWqFh9WZ0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Ldx0i/btsNsEImCAQ/khbOd2EINQB09pWqFh9WZ0/img.png&quot; data-alt=&quot;SimpleJob이라는 객체를 생성한다.&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Ldx0i/btsNsEImCAQ/khbOd2EINQB09pWqFh9WZ0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FLdx0i%2FbtsNsEImCAQ%2FkhbOd2EINQB09pWqFh9WZ0%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;564&quot; height=&quot;361&quot; data-origin-width=&quot;564&quot; data-origin-height=&quot;361&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;SimpleJob이라는 객체를 생성한다.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;5. 리스트 변수의 선언한 Step을 담아서&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;674&quot; data-origin-height=&quot;202&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ddK5d0/btsNumG47De/GEbJxTmcAFIKE4KFcLcke0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ddK5d0/btsNumG47De/GEbJxTmcAFIKE4KFcLcke0/img.png&quot; data-alt=&quot;SimpleJobBuilder start 메서드&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ddK5d0/btsNumG47De/GEbJxTmcAFIKE4KFcLcke0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FddK5d0%2FbtsNumG47De%2FGEbJxTmcAFIKE4KFcLcke0%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;674&quot; height=&quot;202&quot; data-origin-width=&quot;674&quot; data-origin-height=&quot;202&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;SimpleJobBuilder start 메서드&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;5_1. start 메서드를 호출하고 그에 담겨있는 내용은 다음과 같다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;860&quot; data-origin-height=&quot;498&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cnp6lw/btsNt8or1EQ/BD4sJBodTGW1bwEN5WfPmk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cnp6lw/btsNt8or1EQ/BD4sJBodTGW1bwEN5WfPmk/img.png&quot; data-alt=&quot;Step을 담고있는 변수 내용.&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cnp6lw/btsNt8or1EQ/BD4sJBodTGW1bwEN5WfPmk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fcnp6lw%2FbtsNt8or1EQ%2FBD4sJBodTGW1bwEN5WfPmk%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;860&quot; height=&quot;498&quot; data-origin-width=&quot;860&quot; data-origin-height=&quot;498&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;Step을 담고있는 변수 내용.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;6. SimpleJob의 구조는 다음과 같다.&lt;/p&gt;
&lt;div style=&quot;background-color: #1e1f22; color: #bcbec4;&quot;&gt;
&lt;pre class=&quot;gradle&quot;&gt;&lt;code&gt;//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//

package org.springframework.batch.core.job;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import org.springframework.batch.core.BatchStatus;
import org.springframework.batch.core.JobExecution;
import org.springframework.batch.core.JobInterruptedException;
import org.springframework.batch.core.StartLimitExceededException;
import org.springframework.batch.core.Step;
import org.springframework.batch.core.StepExecution;
import org.springframework.batch.core.repository.JobRestartException;
import org.springframework.batch.core.step.StepLocator;

public class SimpleJob extends AbstractJob {
    private List&amp;lt;Step&amp;gt; steps;

    public SimpleJob() {
        this((String)null);
    }

    public SimpleJob(String name) {
        super(name);
        this.steps = new ArrayList();
    }

    public void setSteps(List&amp;lt;Step&amp;gt; steps) {
        this.steps.clear();
        this.steps.addAll(steps);
    }

    public Collection&amp;lt;String&amp;gt; getStepNames() {
        List&amp;lt;String&amp;gt; names = new ArrayList();

        for(Step step : this.steps) {
            names.add(step.getName());
            if (step instanceof StepLocator) {
                names.addAll(((StepLocator)step).getStepNames());
            }
        }

        return names;
    }

    public void addStep(Step step) {
        this.steps.add(step);
    }

    public Step getStep(String stepName) {
        for(Step step : this.steps) {
            if (step.getName().equals(stepName)) {
                return step;
            }

            if (step instanceof StepLocator) {
                Step result = ((StepLocator)step).getStep(stepName);
                if (result != null) {
                    return result;
                }
            }
        }

        return null;
    }

    protected void doExecute(JobExecution execution) throws JobInterruptedException, JobRestartException, StartLimitExceededException {
        StepExecution stepExecution = null;

        for(Step step : this.steps) {
            stepExecution = this.handleStep(step, execution);
            if (stepExecution.getStatus() != BatchStatus.COMPLETED) {
                break;
            }
        }

        if (stepExecution != null) {
            if (logger.isDebugEnabled()) {
                logger.debug(&quot;Upgrading JobExecution status: &quot; + stepExecution);
            }

            execution.upgradeStatus(stepExecution.getStatus());
            execution.setExitStatus(stepExecution.getExitStatus());
        }

    }
}
&lt;/code&gt;&lt;/pre&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;&amp;nbsp;&lt;/p&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;IIII. Job 기본 구성 소스 작성.&lt;/h2&gt;
&lt;div style=&quot;background-color: #1e1f22; color: #bcbec4;&quot;&gt;
&lt;pre class=&quot;crystal&quot;&gt;&lt;code&gt;package io.springbatch.springbatchseulgae;

import lombok.RequiredArgsConstructor;
import org.springframework.batch.core.Job;
import org.springframework.batch.core.Step;
import org.springframework.batch.core.StepContribution;
import org.springframework.batch.core.configuration.annotation.JobBuilderFactory;
import org.springframework.batch.core.configuration.annotation.StepBuilderFactory;
import org.springframework.batch.core.scope.context.ChunkContext;
import org.springframework.batch.core.step.tasklet.Tasklet;
import org.springframework.batch.repeat.RepeatStatus;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
@RequiredArgsConstructor
public class JobConfiguration {

    private final JobBuilderFactory jobBuilderFactory;
    private final StepBuilderFactory stepBuilderFactory;

    @Bean
    public Job job() {
        return jobBuilderFactory.get(&quot;job&quot;)
                .start(step1())
                .next(step2())
                .build();
    }

    @Bean
    public Step step1() {
        return stepBuilderFactory.get(&quot;step1&quot;)
                .tasklet(new Tasklet() {
                    @Override
                    public RepeatStatus execute(StepContribution stepContribution, ChunkContext chunkContext) throws Exception {
                        System.out.println(&quot;step1 was executed&quot;);
                        return RepeatStatus.FINISHED;
                    }
                })
                .build();
    }

    @Bean
    public Step step2() {
        return stepBuilderFactory.get(&quot;step2&quot;)
                .tasklet(new Tasklet() {
                    @Override
                    public RepeatStatus execute(StepContribution stepContribution, ChunkContext chunkContext) throws Exception {
                        System.out.println(&quot;step2 was executed&quot;);
                        return RepeatStatus.FINISHED;
                    }
                })
                .build();
    }

}
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Back-End/SpringBatch</category>
      <category>FlowJob</category>
      <category>job</category>
      <category>simplejob</category>
      <category>spring Batch</category>
      <category>스프링 배치</category>
      <author>슬기로운 개발자</author>
      <guid isPermaLink="true">https://doltae.tistory.com/459</guid>
      <comments>https://doltae.tistory.com/459#entry459comment</comments>
      <pubDate>Mon, 21 Apr 2025 13:37:00 +0900</pubDate>
    </item>
    <item>
      <title>Spring Batch 시작 - DB 스키마 생성(2)</title>
      <link>https://doltae.tistory.com/458</link>
      <description>&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;I. DB 스키마 생성, TABLE별 각 역활 정리.&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1398&quot; data-origin-height=&quot;766&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/pXWzS/btsNtgtBv7Y/XrzUXbJPElbucWXW2SUmpK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/pXWzS/btsNtgtBv7Y/XrzUXbJPElbucWXW2SUmpK/img.png&quot; data-alt=&quot;스키마 관계 구성도&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/pXWzS/btsNtgtBv7Y/XrzUXbJPElbucWXW2SUmpK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FpXWzS%2FbtsNtgtBv7Y%2FXrzUXbJPElbucWXW2SUmpK%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;1398&quot; height=&quot;766&quot; data-origin-width=&quot;1398&quot; data-origin-height=&quot;766&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;스키마 관계 구성도&lt;/figcaption&gt;
&lt;/figure&gt;
&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;@ Job 관련 테이블&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;BATCH_JOB_INSTANCE &lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;select&amp;nbsp;*&amp;nbsp;from&amp;nbsp;BATCH_JOB_INSTANCE;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- Job이 실행될 때 Jobinstance 정보가 저장됨, jom_name과 job_key를 키로 하여 하나의 데이터가 저장.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 동일한 job_name과 job_key로 중복 저장될 수 없다.&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;1426&quot; data-origin-height=&quot;233&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bA7GYV/btsNrV5BFcf/bsJxLHCfiJ6k4VxlqMszxk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bA7GYV/btsNrV5BFcf/bsJxLHCfiJ6k4VxlqMszxk/img.png&quot; data-alt=&quot;컬럼정보&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bA7GYV/btsNrV5BFcf/bsJxLHCfiJ6k4VxlqMszxk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbA7GYV%2FbtsNrV5BFcf%2FbsJxLHCfiJ6k4VxlqMszxk%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;1426&quot; height=&quot;233&quot; data-origin-width=&quot;1426&quot; data-origin-height=&quot;233&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;컬럼정보&lt;/figcaption&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;&lt;b&gt; BATCH_JOB_EXECUTION&lt;/b&gt; &lt;br /&gt;select&amp;nbsp;*&amp;nbsp;from&amp;nbsp;BATCH_JOB_EXECUTION;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- job의 실행정보가 저장되며 Job 생성, 시작/종료 시간, 실행상태, 메세지 등을 관리.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1442&quot; data-origin-height=&quot;330&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bjOKJU/btsNtdxkyRM/GumMbSsWIk53L31d0YVdsk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bjOKJU/btsNtdxkyRM/GumMbSsWIk53L31d0YVdsk/img.png&quot; data-alt=&quot;컬럼정보&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bjOKJU/btsNtdxkyRM/GumMbSsWIk53L31d0YVdsk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbjOKJU%2FbtsNtdxkyRM%2FGumMbSsWIk53L31d0YVdsk%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;1442&quot; height=&quot;330&quot; data-origin-width=&quot;1442&quot; data-origin-height=&quot;330&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;컬럼정보&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;&lt;b&gt;BATCH_JOB_EXECUTION_PARAMS&lt;/b&gt; &lt;br /&gt;select&amp;nbsp;*&amp;nbsp;from&amp;nbsp;BATCH_JOB_EXECUTION_PARAMS;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- Job과 함께 실행되는 JobParameter 정보를 저장&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1452&quot; data-origin-height=&quot;355&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ANiAp/btsNtMMyjpm/rjpVQxpQzZC9BWfTGl5wzK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ANiAp/btsNtMMyjpm/rjpVQxpQzZC9BWfTGl5wzK/img.png&quot; data-alt=&quot;컬럼정보&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ANiAp/btsNtMMyjpm/rjpVQxpQzZC9BWfTGl5wzK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FANiAp%2FbtsNtMMyjpm%2FrjpVQxpQzZC9BWfTGl5wzK%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;1452&quot; height=&quot;355&quot; data-origin-width=&quot;1452&quot; data-origin-height=&quot;355&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;컬럼정보&lt;/figcaption&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; BATCH_JOB_EXECUTION_CONTEXT&lt;/b&gt; &lt;br /&gt;select * from BATCH_JOB_EXECUTION_CONTEXT;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- Job의 실행동안 여러가지 상태정보, 공유 데이터를 직렬화(Json 형식)해서 저장&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- Step간 서로 공유 가능함.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1444&quot; data-origin-height=&quot;161&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bGOibL/btsNtMsgvEF/Zs7JkFQHXAxUqx9vUP8Buk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bGOibL/btsNtMsgvEF/Zs7JkFQHXAxUqx9vUP8Buk/img.png&quot; data-alt=&quot;컬럼정보&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bGOibL/btsNtMsgvEF/Zs7JkFQHXAxUqx9vUP8Buk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbGOibL%2FbtsNtMsgvEF%2FZs7JkFQHXAxUqx9vUP8Buk%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;1444&quot; height=&quot;161&quot; data-origin-width=&quot;1444&quot; data-origin-height=&quot;161&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;컬럼정보&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;@ Step 관련 테이블&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;BATCH_STEP_EXECUTION&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;select&amp;nbsp;*&amp;nbsp;from&amp;nbsp;BATCH_STEP_EXECUTION;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- Step의 실행정보가 저장되어 생성, 시작/종료 시간, 실행상태, 메시지 등을 관리.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1477&quot; data-origin-height=&quot;763&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/W058F/btsNsGTvuXW/R6GnzuK7JvdjTwpXZOgKXk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/W058F/btsNsGTvuXW/R6GnzuK7JvdjTwpXZOgKXk/img.png&quot; data-alt=&quot;컬럼내용&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/W058F/btsNsGTvuXW/R6GnzuK7JvdjTwpXZOgKXk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FW058F%2FbtsNsGTvuXW%2FR6GnzuK7JvdjTwpXZOgKXk%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;1477&quot; height=&quot;763&quot; data-origin-width=&quot;1477&quot; data-origin-height=&quot;763&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;컬럼내용&lt;/figcaption&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; BATCH_STEP_EXECUTION_CONTEXT &lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;/b&gt;select&amp;nbsp;*&amp;nbsp;from&amp;nbsp;BATCH_STEP_EXECUTION_CONTEXT;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- Step의 실행동안 여러가지 상태정보, 공유 데이터를 직렬화(Json 형식)해서 저장&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- Step 별로 저장되어 Step 간 서로 공유할 수 없음.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1413&quot; data-origin-height=&quot;175&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/chm7oJ/btsNsmoc0bd/ZqEFWb1LNGOHfVrLbNhHEk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/chm7oJ/btsNsmoc0bd/ZqEFWb1LNGOHfVrLbNhHEk/img.png&quot; data-alt=&quot;컬럼내용&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/chm7oJ/btsNsmoc0bd/ZqEFWb1LNGOHfVrLbNhHEk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fchm7oJ%2FbtsNsmoc0bd%2FZqEFWb1LNGOHfVrLbNhHEk%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;1413&quot; height=&quot;175&quot; data-origin-width=&quot;1413&quot; data-origin-height=&quot;175&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;컬럼내용&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Back-End/SpringBatch</category>
      <category>batch_job_execution</category>
      <category>batch_job_execution_context</category>
      <category>batch_job_execution_params</category>
      <category>batch_job_instance</category>
      <category>batch_step_execution</category>
      <category>batch_step_execution_context</category>
      <category>job table</category>
      <category>step table</category>
      <author>슬기로운 개발자</author>
      <guid isPermaLink="true">https://doltae.tistory.com/458</guid>
      <comments>https://doltae.tistory.com/458#entry458comment</comments>
      <pubDate>Sun, 20 Apr 2025 18:43:33 +0900</pubDate>
    </item>
    <item>
      <title>Spring Batch 시작 - DB 스키마 생성(1)</title>
      <link>https://doltae.tistory.com/457</link>
      <description>&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;I. 스프링 배치 메타 데이터&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;middot; 스프링 배치의 실행 및 관리를 위한 목적으로 여러 도메인들(Job, Step, JobParameters...)의 정보들을 저장 업데이터, 조회할 수 있는 스키마 구성&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;middot; 과거.. 현재의 실행에 대한 세세한 정보, 실행에 대한 성공과 실패 여부 등을 관리한다.&amp;nbsp;&lt;/p&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;middot; DB 연동할 경우 필수적으로 메타 테이블이 생성되어야 함.&lt;/p&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;II. 스키마 생성 설정&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;middot; 수동 생성 -&amp;gt; 쿼리 복사 후 직접 실행&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;middot; 자동 생성 -&amp;gt; spring.batch.jdbc.initialize-schema 설정&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt; &amp;middot; ALWAYS&lt;/b&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;letter-spacing: 0px;&quot;&gt;- RDBMS 설정이 되어 있을 경우 내장 DB보다 우선적으로 실행&lt;/span&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;&amp;middot; EMBEDDED&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 내장 DB일 때만 실행되며 스키마가 자동 생성됨, 기본값&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;&amp;middot; NEVER&lt;/b&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;- 내장 DB 일경우 스크립트가 생성이 안되기 때문에 오류 발생.&lt;/p&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&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;809&quot; data-origin-height=&quot;446&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/yJcju/btsNsnUuwck/1tm7iPaGszJp4yFWENnX0k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/yJcju/btsNsnUuwck/1tm7iPaGszJp4yFWENnX0k/img.png&quot; data-alt=&quot;application.yml&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/yJcju/btsNsnUuwck/1tm7iPaGszJp4yFWENnX0k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FyJcju%2FbtsNsnUuwck%2F1tm7iPaGszJp4yFWENnX0k%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;809&quot; height=&quot;446&quot; data-origin-width=&quot;809&quot; data-origin-height=&quot;446&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;application.yml&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&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;III. Mysql DB 셋업&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;1. MySQL 서버, WorkBench 설치&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://code-angie.tistory.com/158&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://code-angie.tistory.com/158&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1745130545062&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;[MySQL] MySQL 설치하기 (윈도우 / windows)&quot; data-og-description=&quot;MySQLMySQL은 가장 많이 사용되는 데이터베이스 중 하나이다.무료이기에 간단히 설치해 바로 사용할 수 있다.&amp;nbsp;윈도우와 리눅스 등 다양한 운영체제에서 사용 가능해 확장성이 뛰어나다. 표준 SQL &quot; data-og-host=&quot;code-angie.tistory.com&quot; data-og-source-url=&quot;https://code-angie.tistory.com/158&quot; data-og-url=&quot;https://code-angie.tistory.com/158&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bnWfYc/hyYFywH88S/dqXbVnrOLANAJZ3roA58Nk/img.png?width=800&amp;amp;height=428&amp;amp;face=0_0_800_428,https://scrap.kakaocdn.net/dn/ddSIP8/hyYIaWe03B/bi07KQYIFawjc7ja7Zo0Sk/img.png?width=800&amp;amp;height=428&amp;amp;face=0_0_800_428,https://scrap.kakaocdn.net/dn/HCxDD/hyYFFWT4sm/gBaec5FL0fWBN01sEY1w2K/img.png?width=780&amp;amp;height=588&amp;amp;face=0_0_780_588&quot;&gt;&lt;a href=&quot;https://code-angie.tistory.com/158&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://code-angie.tistory.com/158&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bnWfYc/hyYFywH88S/dqXbVnrOLANAJZ3roA58Nk/img.png?width=800&amp;amp;height=428&amp;amp;face=0_0_800_428,https://scrap.kakaocdn.net/dn/ddSIP8/hyYIaWe03B/bi07KQYIFawjc7ja7Zo0Sk/img.png?width=800&amp;amp;height=428&amp;amp;face=0_0_800_428,https://scrap.kakaocdn.net/dn/HCxDD/hyYFFWT4sm/gBaec5FL0fWBN01sEY1w2K/img.png?width=780&amp;amp;height=588&amp;amp;face=0_0_780_588');&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;[MySQL] MySQL 설치하기 (윈도우 / windows)&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;MySQLMySQL은 가장 많이 사용되는 데이터베이스 중 하나이다.무료이기에 간단히 설치해 바로 사용할 수 있다.&amp;nbsp;윈도우와 리눅스 등 다양한 운영체제에서 사용 가능해 확장성이 뛰어나다. 표준 SQL&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;code-angie.tistory.com&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;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. MySQL WorkBench 실행&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;2086&quot; data-origin-height=&quot;843&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ediHxt/btsNrXhUZgH/ieFxgkFmzdvIKGRHjWHSDK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ediHxt/btsNrXhUZgH/ieFxgkFmzdvIKGRHjWHSDK/img.png&quot; data-alt=&quot;초기화면&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ediHxt/btsNrXhUZgH/ieFxgkFmzdvIKGRHjWHSDK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FediHxt%2FbtsNrXhUZgH%2FieFxgkFmzdvIKGRHjWHSDK%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;2086&quot; height=&quot;843&quot; data-origin-width=&quot;2086&quot; data-origin-height=&quot;843&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;초기화면&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1193&quot; data-origin-height=&quot;709&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cJJdJS/btsNtdQ9Der/jM3816NrmParsbuN1ftJl0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cJJdJS/btsNtdQ9Der/jM3816NrmParsbuN1ftJl0/img.png&quot; data-alt=&quot;사용자 계정 생성&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cJJdJS/btsNtdQ9Der/jM3816NrmParsbuN1ftJl0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcJJdJS%2FbtsNtdQ9Der%2FjM3816NrmParsbuN1ftJl0%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;1193&quot; height=&quot;709&quot; data-origin-width=&quot;1193&quot; data-origin-height=&quot;709&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;사용자 계정 생성&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-start=&quot;191&quot; data-end=&quot;216&quot; data-ke-size=&quot;size23&quot;&gt;새로운 사용자(User) 생성&lt;/h3&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot; data-start=&quot;218&quot; data-end=&quot;655&quot;&gt;
&lt;li data-start=&quot;218&quot; data-end=&quot;344&quot;&gt;&lt;b&gt;좌측 상단의 메뉴 바&lt;/b&gt;에서 Server &amp;gt; Users and Privileges 선택&lt;br /&gt;또는 Navigator 패널에서 Management &amp;gt; Users and Privileges 클릭&lt;/li&gt;
&lt;li data-start=&quot;346&quot; data-end=&quot;416&quot;&gt;상단 탭에서&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;&quot;Users and Privileges&quot;&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;창이 열리면, 좌측에서&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;&quot;Add Account&quot;&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;클릭&lt;/li&gt;
&lt;li data-start=&quot;418&quot; data-end=&quot;655&quot;&gt;사용자 정보 입력:
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot; data-start=&quot;435&quot; data-end=&quot;655&quot;&gt;
&lt;li data-start=&quot;435&quot; data-end=&quot;479&quot;&gt;&lt;b&gt;Login Name&lt;/b&gt;: 새로 만들 사용자명 (예: dev_user)&lt;/li&gt;
&lt;li data-start=&quot;483&quot; data-end=&quot;537&quot;&gt;&lt;b&gt;Limit to Hosts Matching&lt;/b&gt;: 기본값 % (모든 IP에서 접속 허용)&lt;/li&gt;
&lt;li data-start=&quot;541&quot; data-end=&quot;605&quot;&gt;&lt;b&gt;Authentication Type&lt;/b&gt;: 기본값 그대로 (MySQL Native Authentication)&lt;/li&gt;
&lt;li data-start=&quot;609&quot; data-end=&quot;655&quot;&gt;&lt;b&gt;Password / Confirm Password&lt;/b&gt;: 원하는 비밀번호 입력&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&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;1056&quot; data-origin-height=&quot;1092&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/YaFa0/btsNosJuiYI/hoqNZ8eS5wuWuKqQxJXFjk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/YaFa0/btsNosJuiYI/hoqNZ8eS5wuWuKqQxJXFjk/img.png&quot; data-alt=&quot;왼쪽 하단 Add Account 클릭&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/YaFa0/btsNosJuiYI/hoqNZ8eS5wuWuKqQxJXFjk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FYaFa0%2FbtsNosJuiYI%2FhoqNZ8eS5wuWuKqQxJXFjk%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;1056&quot; height=&quot;1092&quot; data-origin-width=&quot;1056&quot; data-origin-height=&quot;1092&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;왼쪽 하단 Add Account 클릭&lt;/figcaption&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&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1784&quot; data-origin-height=&quot;939&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/D01WV/btsNrXvtNLA/6Q6xZPX9QZJWmkYTSR2uJ1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/D01WV/btsNrXvtNLA/6Q6xZPX9QZJWmkYTSR2uJ1/img.png&quot; data-alt=&quot;권한설정&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/D01WV/btsNrXvtNLA/6Q6xZPX9QZJWmkYTSR2uJ1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FD01WV%2FbtsNrXvtNLA%2F6Q6xZPX9QZJWmkYTSR2uJ1%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;1784&quot; height=&quot;939&quot; data-origin-width=&quot;1784&quot; data-origin-height=&quot;939&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;권한설정&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 data-end=&quot;688&quot; data-start=&quot;662&quot; data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;권한(Privileges) 설정&lt;/h3&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-end=&quot;1010&quot; data-start=&quot;690&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li data-end=&quot;786&quot; data-start=&quot;690&quot;&gt;상단의 Administrative Roles 탭으로 이동&lt;br /&gt;또는 Schema Privileges 탭으로 이동하여 특정 데이터베이스에 대한 권한 설정 가능&lt;/li&gt;
&lt;li data-end=&quot;868&quot; data-start=&quot;788&quot;&gt;빠르게 root처럼 전체 권한을 주고 싶다면:
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;868&quot; data-start=&quot;820&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;868&quot; data-start=&quot;820&quot;&gt;Administrative Roles에서 &lt;b&gt;DBA&lt;/b&gt; 체크 (모든 권한 포함)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li data-end=&quot;1010&quot; data-start=&quot;870&quot;&gt;특정 DB만 접근하게 하고 싶다면:
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1010&quot; data-start=&quot;896&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;934&quot; data-start=&quot;896&quot;&gt;Schema Privileges &amp;gt; Add Entry 클릭&lt;/li&gt;
&lt;li data-end=&quot;965&quot; data-start=&quot;938&quot;&gt;특정 스키마 선택 또는 &quot;All Schema&quot;&lt;/li&gt;
&lt;li data-end=&quot;1010&quot; data-start=&quot;969&quot;&gt;필요한 권한 선택 (예: SELECT, INSERT, UPDATE 등)&lt;/li&gt;
&lt;/ul&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;158&quot; data-origin-height=&quot;56&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/pMVIs/btsNs5efMYP/Z62cWHoA1zS2ivLAtJreB1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/pMVIs/btsNs5efMYP/Z62cWHoA1zS2ivLAtJreB1/img.png&quot; data-alt=&quot;Apply 클릭&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/pMVIs/btsNs5efMYP/Z62cWHoA1zS2ivLAtJreB1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FpMVIs%2FbtsNs5efMYP%2FZ62cWHoA1zS2ivLAtJreB1%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;158&quot; height=&quot;56&quot; data-origin-width=&quot;158&quot; data-origin-height=&quot;56&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;Apply 클릭&lt;/figcaption&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;&lt;b&gt;3. MySQL Database 추가&lt;/b&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;CREATE DATABASE springbatch;&lt;br /&gt;show&amp;nbsp;databases;&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;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;537&quot; data-origin-height=&quot;161&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bA7tcP/btsNsT6ql9b/jcazmWCCkBG0FGIap1iVGK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bA7tcP/btsNsT6ql9b/jcazmWCCkBG0FGIap1iVGK/img.png&quot; data-alt=&quot;조회화면&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bA7tcP/btsNsT6ql9b/jcazmWCCkBG0FGIap1iVGK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbA7tcP%2FbtsNsT6ql9b%2FjcazmWCCkBG0FGIap1iVGK%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;537&quot; height=&quot;161&quot; data-origin-width=&quot;537&quot; data-origin-height=&quot;161&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;조회화면&lt;/figcaption&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;&lt;b&gt;4. MySQL Connections 정보 추가&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;285&quot; data-origin-height=&quot;63&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bZRA7N/btsNtlalPoR/cIG7NZBdJ3trPGf92QYk60/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bZRA7N/btsNtlalPoR/cIG7NZBdJ3trPGf92QYk60/img.png&quot; data-alt=&quot;+클릭&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bZRA7N/btsNtlalPoR/cIG7NZBdJ3trPGf92QYk60/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbZRA7N%2FbtsNtlalPoR%2FcIG7NZBdJ3trPGf92QYk60%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;285&quot; height=&quot;63&quot; data-origin-width=&quot;285&quot; data-origin-height=&quot;63&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;+클릭&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;842&quot; data-origin-height=&quot;532&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bfooEw/btsNryQhS0J/bnajOddczqkRdDjTUKHJjK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bfooEw/btsNryQhS0J/bnajOddczqkRdDjTUKHJjK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bfooEw/btsNryQhS0J/bnajOddczqkRdDjTUKHJjK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbfooEw%2FbtsNryQhS0J%2FbnajOddczqkRdDjTUKHJjK%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;842&quot; height=&quot;532&quot; data-origin-width=&quot;842&quot; data-origin-height=&quot;532&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;654&quot; data-origin-height=&quot;243&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ygfV4/btsNrwSrxN8/UayDCRKMWiEgs3jUbq8hXK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ygfV4/btsNrwSrxN8/UayDCRKMWiEgs3jUbq8hXK/img.png&quot; data-alt=&quot;서버 생성 완료.&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ygfV4/btsNrwSrxN8/UayDCRKMWiEgs3jUbq8hXK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FygfV4%2FbtsNrwSrxN8%2FUayDCRKMWiEgs3jUbq8hXK%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;654&quot; height=&quot;243&quot; data-origin-width=&quot;654&quot; data-origin-height=&quot;243&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;서버 생성 완료.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&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;IIII. DB 스키마 생성&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;442&quot; data-origin-height=&quot;319&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/lXJc0/btsNryCJLTW/3wf27rbMUsozxIOT22pKg1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/lXJc0/btsNryCJLTW/3wf27rbMUsozxIOT22pKg1/img.png&quot; data-alt=&quot;인텔리제이 DB 접속 정보 추가&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/lXJc0/btsNryCJLTW/3wf27rbMUsozxIOT22pKg1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FlXJc0%2FbtsNryCJLTW%2F3wf27rbMUsozxIOT22pKg1%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;442&quot; height=&quot;319&quot; data-origin-width=&quot;442&quot; data-origin-height=&quot;319&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;인텔리제이 DB 접속 정보 추가&lt;/figcaption&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&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;834&quot; data-origin-height=&quot;724&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/rTpYw/btsNskRd2hC/iV3vQ8tXf2FkQYFM6xZzjK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/rTpYw/btsNskRd2hC/iV3vQ8tXf2FkQYFM6xZzjK/img.png&quot; data-alt=&quot;접속정보 입력&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/rTpYw/btsNskRd2hC/iV3vQ8tXf2FkQYFM6xZzjK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FrTpYw%2FbtsNskRd2hC%2FiV3vQ8tXf2FkQYFM6xZzjK%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;834&quot; height=&quot;724&quot; data-origin-width=&quot;834&quot; data-origin-height=&quot;724&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;접속정보 입력&lt;/figcaption&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;@ 복사할 DML 스크립트 긁어오기.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;515&quot; data-origin-height=&quot;538&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/voYUM/btsNsh1eztm/aunUHGk4OCg965aKA1HfD1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/voYUM/btsNsh1eztm/aunUHGk4OCg965aKA1HfD1/img.png&quot; data-alt=&quot;sql 스크립트 위치&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/voYUM/btsNsh1eztm/aunUHGk4OCg965aKA1HfD1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FvoYUM%2FbtsNsh1eztm%2FaunUHGk4OCg965aKA1HfD1%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;515&quot; height=&quot;538&quot; data-origin-width=&quot;515&quot; data-origin-height=&quot;538&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;sql 스크립트 위치&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;445&quot; data-origin-height=&quot;552&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cDzcrj/btsNsb1kD2c/u308kGQddbA5fBXMRMdz8k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cDzcrj/btsNsb1kD2c/u308kGQddbA5fBXMRMdz8k/img.png&quot; data-alt=&quot;각 DB 별 스키마 생성 스크립트.&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cDzcrj/btsNsb1kD2c/u308kGQddbA5fBXMRMdz8k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcDzcrj%2FbtsNsb1kD2c%2Fu308kGQddbA5fBXMRMdz8k%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;445&quot; height=&quot;552&quot; data-origin-width=&quot;445&quot; data-origin-height=&quot;552&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;각 DB 별 스키마 생성 스크립트.&lt;/figcaption&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;@ MySQL DB 기준으로 생성합니다.&lt;/p&gt;
&lt;div style=&quot;background-color: #1e1f22; color: #bcbec4;&quot;&gt;
&lt;pre class=&quot;sql&quot;&gt;&lt;code&gt;-- Autogenerated: do not edit this file

CREATE TABLE BATCH_JOB_INSTANCE  (
    JOB_INSTANCE_ID BIGINT  NOT NULL PRIMARY KEY ,
    VERSION BIGINT ,
    JOB_NAME VARCHAR(100) NOT NULL,
    JOB_KEY VARCHAR(32) NOT NULL,
    constraint JOB_INST_UN unique (JOB_NAME, JOB_KEY)
) ENGINE=InnoDB;

CREATE TABLE BATCH_JOB_EXECUTION  (
    JOB_EXECUTION_ID BIGINT  NOT NULL PRIMARY KEY ,
    VERSION BIGINT  ,
    JOB_INSTANCE_ID BIGINT NOT NULL,
    CREATE_TIME DATETIME(6) NOT NULL,
    START_TIME DATETIME(6) DEFAULT NULL ,
    END_TIME DATETIME(6) DEFAULT NULL ,
    STATUS VARCHAR(10) ,
    EXIT_CODE VARCHAR(2500) ,
    EXIT_MESSAGE VARCHAR(2500) ,
    LAST_UPDATED DATETIME(6),
    JOB_CONFIGURATION_LOCATION VARCHAR(2500) NULL,
    constraint JOB_INST_EXEC_FK foreign key (JOB_INSTANCE_ID)
    references BATCH_JOB_INSTANCE(JOB_INSTANCE_ID)
) ENGINE=InnoDB;

CREATE TABLE BATCH_JOB_EXECUTION_PARAMS  (
    JOB_EXECUTION_ID BIGINT NOT NULL ,
    TYPE_CD VARCHAR(6) NOT NULL ,
    KEY_NAME VARCHAR(100) NOT NULL ,
    STRING_VAL VARCHAR(250) ,
    DATE_VAL DATETIME(6) DEFAULT NULL ,
    LONG_VAL BIGINT ,
    DOUBLE_VAL DOUBLE PRECISION ,
    IDENTIFYING CHAR(1) NOT NULL ,
    constraint JOB_EXEC_PARAMS_FK foreign key (JOB_EXECUTION_ID)
    references BATCH_JOB_EXECUTION(JOB_EXECUTION_ID)
) ENGINE=InnoDB;

CREATE TABLE BATCH_STEP_EXECUTION  (
    STEP_EXECUTION_ID BIGINT  NOT NULL PRIMARY KEY ,
    VERSION BIGINT NOT NULL,
    STEP_NAME VARCHAR(100) NOT NULL,
    JOB_EXECUTION_ID BIGINT NOT NULL,
    START_TIME DATETIME(6) NOT NULL ,
    END_TIME DATETIME(6) DEFAULT NULL ,
    STATUS VARCHAR(10) ,
    COMMIT_COUNT BIGINT ,
    READ_COUNT BIGINT ,
    FILTER_COUNT BIGINT ,
    WRITE_COUNT BIGINT ,
    READ_SKIP_COUNT BIGINT ,
    WRITE_SKIP_COUNT BIGINT ,
    PROCESS_SKIP_COUNT BIGINT ,
    ROLLBACK_COUNT BIGINT ,
    EXIT_CODE VARCHAR(2500) ,
    EXIT_MESSAGE VARCHAR(2500) ,
    LAST_UPDATED DATETIME(6),
    constraint JOB_EXEC_STEP_FK foreign key (JOB_EXECUTION_ID)
    references BATCH_JOB_EXECUTION(JOB_EXECUTION_ID)
) ENGINE=InnoDB;

CREATE TABLE BATCH_STEP_EXECUTION_CONTEXT  (
    STEP_EXECUTION_ID BIGINT NOT NULL PRIMARY KEY,
    SHORT_CONTEXT VARCHAR(2500) NOT NULL,
    SERIALIZED_CONTEXT TEXT ,
    constraint STEP_EXEC_CTX_FK foreign key (STEP_EXECUTION_ID)
    references BATCH_STEP_EXECUTION(STEP_EXECUTION_ID)
) ENGINE=InnoDB;

CREATE TABLE BATCH_JOB_EXECUTION_CONTEXT  (
    JOB_EXECUTION_ID BIGINT NOT NULL PRIMARY KEY,
    SHORT_CONTEXT VARCHAR(2500) NOT NULL,
    SERIALIZED_CONTEXT TEXT ,
    constraint JOB_EXEC_CTX_FK foreign key (JOB_EXECUTION_ID)
    references BATCH_JOB_EXECUTION(JOB_EXECUTION_ID)
) ENGINE=InnoDB;

CREATE TABLE BATCH_STEP_EXECUTION_SEQ (
    ID BIGINT NOT NULL,
    UNIQUE_KEY CHAR(1) NOT NULL,
    constraint UNIQUE_KEY_UN unique (UNIQUE_KEY)
) ENGINE=InnoDB;

INSERT INTO BATCH_STEP_EXECUTION_SEQ (ID, UNIQUE_KEY) select * from (select 0 as ID, '0' as UNIQUE_KEY) as tmp where not exists(select * from BATCH_STEP_EXECUTION_SEQ);

CREATE TABLE BATCH_JOB_EXECUTION_SEQ (
    ID BIGINT NOT NULL,
    UNIQUE_KEY CHAR(1) NOT NULL,
    constraint UNIQUE_KEY_UN unique (UNIQUE_KEY)
) ENGINE=InnoDB;

INSERT INTO BATCH_JOB_EXECUTION_SEQ (ID, UNIQUE_KEY) select * from (select 0 as ID, '0' as UNIQUE_KEY) as tmp where not exists(select * from BATCH_JOB_EXECUTION_SEQ);

CREATE TABLE BATCH_JOB_SEQ (
    ID BIGINT NOT NULL,
    UNIQUE_KEY CHAR(1) NOT NULL,
    constraint UNIQUE_KEY_UN unique (UNIQUE_KEY)
) ENGINE=InnoDB;

INSERT INTO BATCH_JOB_SEQ (ID, UNIQUE_KEY) select * from (select 0 as ID, '0' as UNIQUE_KEY) as tmp where not exists(select * from BATCH_JOB_SEQ);
&lt;/code&gt;&lt;/pre&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;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1524&quot; data-origin-height=&quot;1077&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bWJssb/btsNpUZz8j7/7a1KkyLbiOxtd8lguSBaS0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bWJssb/btsNpUZz8j7/7a1KkyLbiOxtd8lguSBaS0/img.png&quot; data-alt=&quot;붙여넣기.&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bWJssb/btsNpUZz8j7/7a1KkyLbiOxtd8lguSBaS0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbWJssb%2FbtsNpUZz8j7%2F7a1KkyLbiOxtd8lguSBaS0%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;1524&quot; height=&quot;1077&quot; data-origin-width=&quot;1524&quot; data-origin-height=&quot;1077&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;붙여넣기.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;356&quot; data-origin-height=&quot;271&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cZHGnK/btsNrcMdc9k/oBKyEo5cUJEuoQ285CwNF1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cZHGnK/btsNrcMdc9k/oBKyEo5cUJEuoQ285CwNF1/img.png&quot; data-alt=&quot;table 생성 완료.&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cZHGnK/btsNrcMdc9k/oBKyEo5cUJEuoQ285CwNF1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcZHGnK%2FbtsNrcMdc9k%2FoBKyEo5cUJEuoQ285CwNF1%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;356&quot; height=&quot;271&quot; data-origin-width=&quot;356&quot; data-origin-height=&quot;271&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;table 생성 완료.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;@ mysql DB를 사용하기 위한 pom.xml 의존성 추가.&lt;/p&gt;
&lt;div style=&quot;background-color: #1e1f22; color: #bcbec4;&quot;&gt;
&lt;pre class=&quot;xml&quot;&gt;&lt;code&gt;&amp;lt;dependency&amp;gt;
    &amp;lt;groupId&amp;gt;mysql&amp;lt;/groupId&amp;gt;
    &amp;lt;artifactId&amp;gt;mysql-connector-java&amp;lt;/artifactId&amp;gt;
    &amp;lt;scope&amp;gt;runtime&amp;lt;/scope&amp;gt;
&amp;lt;/dependency&amp;gt;&lt;/code&gt;&lt;/pre&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;@application.yml 속성에&lt;/p&gt;
&lt;div style=&quot;background-color: #1e1f22; color: #bcbec4;&quot;&gt;
&lt;pre class=&quot;bash&quot; data-ke-language=&quot;bash&quot;&gt;&lt;code&gt;# MYSQL 설정
spring:
  config:
    activate:
      on-profile: mysql
  datasource:
    hikari:
      jdbc-url: jdbc:mysql://localhost:3306/springbatch?useUnicode=true@characterEncoding=utf8
      username: seulgae
      password: 12345678
      driver-class-name: com.mysql.cj.jdbc.Driver
  batch:
    jdbc:
      initialize-schema: always&lt;/code&gt;&lt;/pre&gt;
&lt;/div&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;</description>
      <category>Back-End/SpringBatch</category>
      <category>mysql</category>
      <category>mysql 사용자 생성</category>
      <category>mysql 서버생성</category>
      <category>mysql설치</category>
      <category>SpringBatch</category>
      <category>배치 메타테이블</category>
      <category>스프링 배치 메타 데이터</category>
      <category>테이블 생성</category>
      <author>슬기로운 개발자</author>
      <guid isPermaLink="true">https://doltae.tistory.com/457</guid>
      <comments>https://doltae.tistory.com/457#entry457comment</comments>
      <pubDate>Sun, 20 Apr 2025 15:43:00 +0900</pubDate>
    </item>
    <item>
      <title>SpringBatch Hello Spring Batch 시작하기</title>
      <link>https://doltae.tistory.com/456</link>
      <description>&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;I. 스프링 배치 초기 선언 어노테이션&lt;/h2&gt;
&lt;div style=&quot;background-color: #1e1f22; color: #bcbec4;&quot;&gt;
&lt;pre class=&quot;bash&quot; data-ke-language=&quot;bash&quot;&gt;&lt;code&gt;@SpringBootApplication
@EnableBatchProcessing // 스프링 배치 초기 선언 어노테이션
public class SpringBatchApplication {

    public static void main(String[] args) {
        SpringApplication.run(SpringBatchApplication.class, args);
    }

}&lt;/code&gt;&lt;/pre&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;@EnableBatchProcessing&lt;/b&gt; &lt;br /&gt;총 4개의 설정 클래스를 실행, 스프링 배치의 모든 초기화 및 실행 구성이 이뤄짐. &lt;br /&gt;스프링 부트 배치의 자동 설정 클래스가 실행됨으로 빈으로 등록된 모든 Job을 검색해서 초기화와 동시에 Job을 수행하도록 구성. &lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;II.&lt;span&gt; 스프링 배치 초기화 설정 클래스 &lt;/span&gt;&lt;/h2&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;1. SimpleBatchConfiguration &lt;br /&gt;- JobBuilderFactory와 StepBuilderFactory 생성, Job과 Step 생성용 &lt;br /&gt;- 스프링 배치의 주요 구성 요소 생성 - 프록시 객체로 생성됨.&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;br /&gt;Q. 프록시 객체란 : 대리인 역활을 하는 객체, 누군가 대신해서 일을 처리해주는 대리인 &lt;br /&gt;A. Proxy(대리인) -&amp;gt; Target(대상) &lt;br /&gt;&lt;br /&gt;2. BatchConfigurerConfiguration &lt;br /&gt;&amp;nbsp;a. BasicBatchConfigurer &lt;br /&gt;- SimpleBatchConfiguration에서 생성한 프록시 객체의 실제 대상 객체를 설정하는 설정 클래스 &lt;br /&gt;- Bean으로 의존성 주입 받아서 주요 객체들을 참조해서 사용할 수 있음. &lt;br /&gt;&lt;br /&gt;b. JpaBatchConfigurer &lt;br /&gt;- JPA 관련 객체를 생성하는 설정 클래스 &lt;br /&gt;- 사용자 정의 BatchConfigurer 인터페이스를 사용할 수 있음. &lt;br /&gt;&lt;br /&gt;3. BatchAutoConfiguration &lt;br /&gt;- 스프링 배치가 초기화 될 때 자동으로 실행되는 설정 클래스 &lt;br /&gt;- Job을 수행하는 JobLauncherApplicationRunner 빈을 생성&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;III.&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;스프링 배치 Job 기본 구성&lt;/span&gt;&lt;/h2&gt;
&lt;div style=&quot;background-color: #1e1f22; color: #bcbec4;&quot;&gt;
&lt;pre class=&quot;kotlin&quot;&gt;&lt;code&gt;package io.springbatch.springbatchseulgae;

import lombok.RequiredArgsConstructor;
import org.springframework.batch.core.Job;
import org.springframework.batch.core.Step;
import org.springframework.batch.core.StepContribution;
import org.springframework.batch.core.configuration.annotation.JobBuilderFactory;
import org.springframework.batch.core.configuration.annotation.StepBuilderFactory;
import org.springframework.batch.core.scope.context.ChunkContext;
import org.springframework.batch.core.step.tasklet.Tasklet;
import org.springframework.batch.repeat.RepeatStatus;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@RequiredArgsConstructor // @Autowired 의존성 주입
@Configuration // 하나의 배치 Job을 정의하고 빈 설정
public class HelloJobConfiguration {

     private final JobBuilderFactory jobBuilderFactory; // Job을 생성하는 빌더 팩토리
     private final StepBuilderFactory stepBuilderFactory; // Step을 생성하는 빌더 팩토리

    @Bean
    public Job helloJob() { // helloJob 이름으로 Job 생성
        return jobBuilderFactory.get(&quot;hello Job&quot;)
                .start(helloStep1())
                .next(helloStep2())
                .build();
    }

    @Bean
    public Step helloStep1() { // helloStep 이름으로 Step생성
        return stepBuilderFactory.get(&quot;helloStep1&quot;)
                .tasklet(new Tasklet() { // Step 안에서 단일 태스크로 수행되는 로직 구현
                    @Override
                    public RepeatStatus execute(StepContribution stepContribution, ChunkContext chunkContext) throws Exception {
                        // 내용기술
                        System.out.println(&quot;Step1 테스트&quot;);

                        // Step 안 Tasklet은 무한 반복됨.
                        // 그래서 return 문에
                        // RepeatStatus을 사용해서 종료처리할 수 있음.
                        return RepeatStatus.FINISHED;
                    }
                })
                .build()
                ;
    }

    @Bean
    public Step helloStep2() {
        return stepBuilderFactory.get(&quot;helloStep1&quot;)
                .tasklet(new Tasklet() {
                    @Override
                    public RepeatStatus execute(StepContribution stepContribution, ChunkContext chunkContext) throws Exception {
                        // 내용기술
                        System.out.println(&quot;Step2 테스트&quot;);

                        return RepeatStatus.FINISHED;
                    }
                })
                .build()
                ;
    }

    // 최종 동작 : Job 구동 -&amp;gt; Step을 실행 -&amp;gt; Teskelt을 실행

}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Back-End/SpringBatch</category>
      <category>@enablebatchprocessing</category>
      <category>batchautoconfiguration</category>
      <category>batchconfigurerconfiguration</category>
      <category>jpabatchconfigurer</category>
      <category>simplebatchconfiguration</category>
      <category>SpringBatch</category>
      <category>스프링 배치</category>
      <author>슬기로운 개발자</author>
      <guid isPermaLink="true">https://doltae.tistory.com/456</guid>
      <comments>https://doltae.tistory.com/456#entry456comment</comments>
      <pubDate>Sun, 20 Apr 2025 14:31:00 +0900</pubDate>
    </item>
    <item>
      <title>Spring Batch 개요</title>
      <link>https://doltae.tistory.com/455</link>
      <description>&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;I. 배치 핵심 패턴&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&amp;middot;&lt;span&gt;&lt;b&gt; Read&lt;/b&gt; - 데이터베이스, 파일, 큐에서 다량의 데이터를 조회한다. (추출)&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;middot; &lt;b&gt;Process&lt;/b&gt; - 특정 방법으로 데이터를 가공한다. (변형)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;middot; &lt;b&gt;Write&lt;/b&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 style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;@ DB에서 사용하는 ETL 작업과 비슷&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;E : Extract(추출)&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 여러 출처(데이터베이스, API, 로그 파일 등)에서 &lt;b&gt;데이터를 끌어오는 단계&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ex : MySQL, Oracle, CSV 파일, 외부 시스템 등에서 데이터 수집&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;T : Transform(변환)&lt;/b&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;ex : 불필요한 컬럼 제거, 날짜 형식 통일, 코드값 변환, 집계 처리 등&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;L : Load(적재)&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 가공한 데이터를 목적지(DB, 데이터 웨어하우스 등)에 저장&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ex : 정제된 데이터를 분석용 데이터베이스에 적재&lt;/p&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;II. 배치 시나리오&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt; &amp;middot; 배치 프로세스를 주기적으로 커밋 &lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 최소한의 자원을 가지고 최대한의 성능을 낼 수 있는 커밋 전략, Spring Batch에서 해당 기능을 제공&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; &amp;middot; 동시 다발적인 Job의 배치 처리, 대용량 병렬 처리&lt;/b&gt;&lt;b&gt;&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;하나의 스레드가 아닌 멀티 스레드로 데이터를 처리.&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;&amp;middot;&lt;span&gt; 실패 후 수동 또는 스케줄링에 의한 재시작&lt;/span&gt;&lt;/b&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;&amp;middot; 의존관계가 있는 step 여러 개를 순차적으로 처리&lt;/b&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;&amp;middot;&lt;span&gt; 조건적 Flow 구성을 통한 체계적이고 유연한 배치 모델 구성&lt;/span&gt;&lt;/b&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;&amp;middot; 반복, 재시도, Skip 처리&lt;/b&gt;&lt;/p&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;III. Spring Batch 아키텍처&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;@ Application&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;middot;&lt;span&gt;&lt;b&gt; 스프링 배치 프레임워크&lt;/b&gt;를 통해 개발자가 만든 &lt;b&gt;모든 배치 Job&lt;/b&gt;과 커스텀 코드를 포함.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;middot; 개발자는 &lt;b&gt;업무로직의 구현에만 집중&lt;/b&gt;하고&lt;b&gt; 공통적인 기반 기술&lt;/b&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;@ Batch Core&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;middot; Job을 &lt;b&gt;실행, 모니터링, 관리&lt;/b&gt;하는 API로 구성되어 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;middot; JobLauncher, Job, Step, Flow 등이 속한다.&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;@ Batch Infrastructure&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;middot; Application, Core 모두 공통 Infrastructure 위에서 빌드한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;middot; Job 실행의 흐름과 처리를 위한 틀을 제공한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;middot; Reader, Processor Writer, Skip, Retry 등이 속한다.&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 alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1472&quot; data-origin-height=&quot;71&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/QP9KF/btsNrrjfC11/eI6wUnk7UcSfUbkTf7JfV0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/QP9KF/btsNrrjfC11/eI6wUnk7UcSfUbkTf7JfV0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/QP9KF/btsNrrjfC11/eI6wUnk7UcSfUbkTf7JfV0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FQP9KF%2FbtsNrrjfC11%2FeI6wUnk7UcSfUbkTf7JfV0%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;440&quot; height=&quot;71&quot; data-origin-width=&quot;1472&quot; data-origin-height=&quot;71&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;</description>
      <category>Back-End/SpringBatch</category>
      <category>SpringBatch</category>
      <category>배치 시나리오</category>
      <category>배치 아키텍처</category>
      <category>스프링 배치</category>
      <author>슬기로운 개발자</author>
      <guid isPermaLink="true">https://doltae.tistory.com/455</guid>
      <comments>https://doltae.tistory.com/455#entry455comment</comments>
      <pubDate>Sat, 19 Apr 2025 17:32:46 +0900</pubDate>
    </item>
    <item>
      <title>클라이언트 요청이란?</title>
      <link>https://doltae.tistory.com/444</link>
      <description>&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;클라이언트 요청은 브라우저, 모바일 앱,다른 서버 등 다양한 클라이언트가 서버에 HTTP 프로토콜을 사용해 정보를 요청하는 행위입니다. 이 요청은 HTTP 메서드 (GET, POST, PUT, DELETE 등)와 함께 특정 URL을 통해 전달됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;I. 클라이언트 요청의 구성 요소&lt;/b&gt;&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;1. HTTP 메서드&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;middot; &lt;b&gt;GET&lt;/b&gt;: 데이터 조회를 요청 (예: /products에서 상품 목록 조회).&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;middot; &lt;b&gt;POST&lt;/b&gt;: 서버에 데이터 전송 및 리소스 생성 요청 (예: /products에서 상품 추가).&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;middot; &lt;b&gt;PUT&lt;/b&gt;: 기존 데이터를 수정 요청 (예: /products/1에서 상품 정보 업데이트).&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;middot; &lt;b&gt;DELETE&lt;/b&gt;: 특정 데이터를 삭제 요청 (예: /products/1에서 상품 삭제).&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;span style=&quot;color: #333333; text-align: start;&quot;&gt;2.&lt;span&gt; URL(Path)&lt;/span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;middot; 클라이언트가 원하는 리소스에 접근하기 위한 경로.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &lt;b&gt;예:&lt;/b&gt; /users/123는 사용자 ID가 123인 사용자의 데이터를 요청.&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;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;3. HTTP 요청 헤더&lt;/span&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;&amp;middot; 요청에 대한 부가 정보를 포함. (예: 인증 토큰, 콘텐츠 타입)&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1737524738911&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Authorization: Bearer &amp;lt;토큰&amp;gt;
Content-Type: application/json&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;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;4. HTTP 요청 본문(Body)&lt;/span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;middot; POST 또는 PUT 요청에서 주로 사용되며, 서버에 전송할 데이터를 포함.&lt;/p&gt;
&lt;pre id=&quot;code_1737524863757&quot; class=&quot;json&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;html&quot;&gt;&lt;code&gt;{
  &quot;name&quot;: &quot;Product A&quot;,
  &quot;price&quot;: 100
}&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;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;5. Spring Controller에서 요청 처리 흐름.&lt;/span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;1. 클라이언트 요청이 DispatcherServlet으로 전달.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;2. 요청 URL 및 HTTP 메서드에 따라 적절한 컨트롤러 메서드로 매핑.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;3. 요청 데이터(경로 변수, 요청 파라미터, HTTP 본문 등)가 컨트롤러 메서드로 전달.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;4. 컨트롤러 메서드가 요청을 처리하고 응답을 생성하거나 서비스 계층에 작업을 위임.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Back-End/Spring</category>
      <author>슬기로운 개발자</author>
      <guid isPermaLink="true">https://doltae.tistory.com/444</guid>
      <comments>https://doltae.tistory.com/444#entry444comment</comments>
      <pubDate>Wed, 22 Jan 2025 14:40:06 +0900</pubDate>
    </item>
    <item>
      <title>Spring MVC 패턴</title>
      <link>https://doltae.tistory.com/443</link>
      <description>&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;I. Spring MVC란?&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;middot; &lt;b&gt;Model-View-Controller&lt;/b&gt; 아키텍처 패턴을 기반으로 한 Spring Framework의 웹 애플리케이션 개발 모듈이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;middot; 애플리케이션의 각 관심사를 명확히 분리하여 유연하고 유지보수하기 쉬운 코드를 작성가능.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;1. 주요 구성 요소 &lt;/b&gt;&lt;/h4&gt;
&lt;h4 style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;@ Model&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;middot; 애플리케이션의 데이터와 비즈니스 로직을 담당.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;middot; 데이터를 처리하거나 DB와 상호작용하는 역할.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;middot; 데이터 객체(VO, DTO)와 이를 처리하는 서비스 계층이 포함될 수 있음.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;@ View&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;middot; 사용자에게 데이털르 표시하는 역활.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;middot; HTML, JSP, Thymeleaf 등 다양한 템플릿 엔진을 통해 구현 가능.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;middot; 사용자 경험(UX)을 담당하며, 컨트롤러가 전달한 데이터를 표시.&lt;/p&gt;
&lt;h4 style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;@ Controller&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;middot; 사용자의 요청을 처리하고 적절한 응답을 반환하는 역할.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;middot; 비즈니스 로직을 호출하고, 결과 데이터를 모델에 담아 뷰에 전달.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;middot; Spring에서는 @Controller 또는 @RestController 애노테이션으로 정의.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;2.&lt;span&gt; Spring MVC 동작 흐름&lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span&gt;1. 클라이언트 요청 &lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;middot; 클라이언트가 특정 URL로 요청을 보냄.&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&gt;2.&lt;span&gt; DispatcherServlet &lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;middot; 모든 요청은 DispatcherServlet이 가장 먼저 받음.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;middot; 이 서블릿은 프론트 컨트롤러 역할을 하며, 요청을 적절한 컨트롤러로 라우팅.&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&gt;3.&lt;span&gt;&lt;span&gt; HandlerMapping &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;middot; DispatcherServlet은 HandlerMapping을 통해 요청에 매핑되는 컨트롤러를 찾음.&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&gt;4.&lt;span&gt;&lt;span&gt;&lt;span&gt; Controller 호출 &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;middot; 매핑된 컨트롤러가 호출되고, 요청을 처리.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;middot; 서비스 계층을 호출해 비즈니스 로직 실행.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;middot; 처리 결과 데이터를 모델 객체에 저장.&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&gt;5.&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt; ViewResolver &lt;/span&gt;호출&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;middot; DispatcherServlet은 뷰 이름을 ViewResolver에 전달.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;middot; ViewResolver는 적절한 뷰(JSP, Thymeleaf 등)를 선택하여 클라이언트에게 전달할 응답을 생성.&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&gt;6.&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;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;middot; 클라이언트가 요청한 결과를 뷰를 통해 렌더링하여 반환.&lt;/p&gt;
&lt;h4 style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;3.&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;Spring MVC의 장점.&lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&amp;middot;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;b&gt;유지보수성:&lt;/b&gt; 관심사의 분리를 통해 코드 가독성과 유지보수가 쉬움.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;middot; &lt;b&gt;유연성:&lt;/b&gt; 다양한 뷰 기술(JSP, Thymeleaf, JSON 등)과 쉽게 통합.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;middot; &lt;b&gt;확장성:&lt;/b&gt; 의존성 주입과 AOP를 통한 확장 가능.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;middot; &lt;b&gt;REST 지원:&lt;/b&gt; RESTful 웹 서비스 개발에 최적화된 기능 제공.&lt;/p&gt;</description>
      <category>Back-End/Spring</category>
      <category>Controller</category>
      <category>framework</category>
      <category>Model</category>
      <category>MVC</category>
      <category>spring</category>
      <category>View</category>
      <author>슬기로운 개발자</author>
      <guid isPermaLink="true">https://doltae.tistory.com/443</guid>
      <comments>https://doltae.tistory.com/443#entry443comment</comments>
      <pubDate>Wed, 22 Jan 2025 13:47:44 +0900</pubDate>
    </item>
    <item>
      <title>Java 컬렉션 프레임워크인가 아닌가..?</title>
      <link>https://doltae.tistory.com/442</link>
      <description>&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size14&quot;&gt;2025년 01월 20일 직장 후배가 질문한 내용에 답변을 못했다.&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size14&quot;&gt;정말 어려운 질문이고 좋은 질문이지만 제대로 답변하지 못하여 공부하고자 만들어 본 포스팅이다.&lt;/p&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;A. 선배님 자바 컬렉션 인터페이스는 개발자가 직접 호출하고 프레임워크 성격을 띄지 않고 있는거 같은데 왜 프레임워크라고 하는지 모르겠습니다.&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;자바 컬렉션을 직접 호출하여 사용하는 것만으로는 프레임워크의 특징은 &quot;제어의 역전(Inversion of Control, IoC)&quot;를 명확하게 느낄 수 없기 때문에 질문한 내용.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;1. 프레임워크란?&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;middot; 특정한 작업을 쉽게 할 수 있도록 설계된, 일련의 규칙과 구조를 제공하는 소프트웨어 시스템&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&amp;middot;&lt;b&gt; 일반적인 구조를 제공하고, 세부적인 구현을 개발자가 확장하는 것!!&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%; height: 89px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 14.3023%; height: 20px;&quot;&gt;&lt;b&gt;구분&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 85.6977%; height: 20px;&quot;&gt;&lt;b&gt;설명&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 14.3023%; height: 17px;&quot;&gt;구조&lt;/td&gt;
&lt;td style=&quot;width: 85.6977%; height: 17px;&quot;&gt;코드 조직을 위한 체계적인 방식.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 18px;&quot;&gt;
&lt;td style=&quot;width: 14.3023%; height: 18px;&quot;&gt;표준화&lt;/td&gt;
&lt;td style=&quot;width: 85.6977%; height: 18px;&quot;&gt;일관된 규칙과 인터페이스 제공.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 14.3023%; height: 17px;&quot;&gt;재사용 가능성&lt;/td&gt;
&lt;td style=&quot;width: 85.6977%; height: 17px;&quot;&gt;여러 프로젝트에서 활용 가능.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 14.3023%; height: 17px;&quot;&gt;확장성&lt;/td&gt;
&lt;td style=&quot;width: 85.6977%; height: 17px;&quot;&gt;필요에 따라 커스터마이징 가능.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;2. 라이브러리란?&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;middot; 라이브러리는 특정 기능을 수행하는 재사용 가능한 코드이 집합.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt; &amp;middot; 개발자가 필요할 때 호출해서 사용하는 도구로 제어권은 전적으로 개발자에게 있다.&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;middot; 라이브러리는 특정 문제를 해결하거나 기능을 쉽게 구현하도록 도와주는 역할&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;3. 제어의 역전(Inversion of Control, IoC)란?&lt;/b&gt;&lt;b&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;middot; &lt;b&gt;제어의 역전&lt;/b&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;이란, 프로그램의 흐름을&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;b&gt;프레임워크&lt;/b&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;가 제어하고, 개발자는 그 흐름에 맞게 특정 작업을 수행하는 방식입니다. 즉, 개발자는 &quot;어디서, 어떻게, 무엇을 호출할지&quot;를 결정하는 것이 아니라,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;b&gt;프레임워크가 그 흐름을 결정하고, 개발자는 특정 작업만 수행&lt;/b&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 style=&quot;color: #333333; text-align: start;&quot;&gt;&amp;middot;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;b&gt; 예시&lt;/b&gt;: Spring Framework&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&amp;middot;&lt;b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt; Spring에서는 의존성 주입(DI)을 통해 객체를 생성하고 관리합니다. 개발자는 객체를 직접 생성하지 않고, 프레임워크(Spring)가 객체를 생성하고 &lt;b&gt;애플리케이션의 흐름&lt;/b&gt;을 제어합니다. 이처럼 &lt;b&gt;Spring&lt;/b&gt;은 제어의 역전을 따릅니다.&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;4. 모든 프레임워크에서 제어의 역전이 필수적이지 않다.&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;자바의 &lt;b&gt;컬렉션 프레임워크&lt;/b&gt;와 같은 경우, 개발자가 &lt;b&gt;컬렉션을 명시적으로 호출&lt;/b&gt;하고 관리합니다. 즉, &lt;b&gt;컬렉션 프레임워크&lt;/b&gt;는 &lt;b&gt;데이터 관리의 표준화된 방법과 알고리즘&lt;/b&gt;을 제공하지만, &lt;b&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;프로그램의 흐름을 제어하지는 않기 때문에 제어의 역전이 적용되지 않는다.&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;5. 프레임워크에서 제어의 역전이 적용되지 않는 경우&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;middot; 제어의 역전은 주로 &lt;b&gt;애플리케이션의 구조와 흐름을 제어하는 프레임워크&lt;/b&gt;에서 사용됨.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;middot; 하지만 &lt;b&gt;도구&lt;/b&gt;나 &lt;b&gt;라이브러리&lt;/b&gt;에서는 제어의 역전이 요구되지 않습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;middot; 예를 들어:&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;b&gt;직접 호출&lt;/b&gt;하고 제어합니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;JDBC&lt;/b&gt;: 데이터베이스와의 연결을 위한 도구이므로, 사용자가 &lt;b&gt;직접 연결&lt;/b&gt;하고 &lt;b&gt;쿼리를 실행&lt;/b&gt;하는 방식입니다.&lt;/li&gt;
&lt;/ul&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 data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;6.&lt;span&gt; 결론.&lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;일반적으로 프레임워크는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;제어의 역전&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;원칙을 따름. 즉, 개발자는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;프레임워크에 의해 호출&lt;/b&gt;되고, 그 안에서 특정한 작업을 하게 됩니다. 예를 들어,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;Spring 프레임워크&lt;/b&gt;에서는 애플리케이션의 흐름과 객체 생성 등을&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;Spring&lt;/b&gt;이 관리하고, 개발자는 이를 이용하여 애플리케이션을 개발합니다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&amp;nbsp;자바 컬렉션에서는 개발자가 직접 컬렉션을 호출하고 사용하는 방식이라 제어의 역전이 명확하지 않습니다.&lt;/span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/b&gt;그럼에도 불구하고,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;데이터를 다루는 일련의 작업을 표준화&lt;/b&gt;하고, 개발자가 이를 효율적으로 재사용할 수 있게 해주는 점에서&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;프레임워크&lt;/b&gt;로 분류할 수 있습니다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;7.&lt;span&gt;&lt;span&gt; 느낀점.&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/h4&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;391&quot; data-origin-height=&quot;384&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/wIOWT/btsLUt9pZNZ/85gpYDE9pP3bvTWesPffgk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/wIOWT/btsLUt9pZNZ/85gpYDE9pP3bvTWesPffgk/img.png&quot; data-alt=&quot;이마딱&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/wIOWT/btsLUt9pZNZ/85gpYDE9pP3bvTWesPffgk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FwIOWT%2FbtsLUt9pZNZ%2F85gpYDE9pP3bvTWesPffgk%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;391&quot; height=&quot;384&quot; data-origin-width=&quot;391&quot; data-origin-height=&quot;384&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;이마딱&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;A. 조금 더 쉬운 설명(추가)&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&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; 물컵은 객체 또는 데이터를 담는 그릇으로 비유할 수 있어요. 이는 개발 과정에서 우리가 다루는 핵심 단위(예: 클래스나 객체)라고 볼 수 있죠.&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;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;/li&gt;
&lt;li&gt;개발자가 &lt;b&gt;직접 라이브러리를 호출&lt;/b&gt;해서 필요한 작업(물을 따르는 것)을 수행합니다. 즉, 개발자가 &quot;어디에서&quot; 물을 따를지와 같은 제어권을 가집니다.&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;b&gt;세상&lt;/b&gt; 또는 &lt;b&gt;정해진 환경&lt;/b&gt;으로 비유할 수 있습니다.&lt;/li&gt;
&lt;li&gt;이 세상은 물컵에 물을 따르는 과정 전체를 이미 정의하고 있습니다.&lt;/li&gt;
&lt;li&gt;&quot;물을 언제, 어떻게 따를지&quot;는 이미 정해져 있고, 개발자는 물컵만 준비해서 이 세상(프레임워크) 규칙에 맞게 맡기기만 하면 됩니다.&lt;/li&gt;
&lt;li&gt;제어권이 프레임워크에 있습니다. 이걸 흔히 **제어의 역전(Inversion of Control)**이라고 합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&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; 당신이 물컵을 들고 &quot;내가 물을 따를 거야&quot;라고 주도적으로 행동하는 것.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;프레임워크:&lt;/b&gt; 이미 정해진 환경(세상)이 &quot;네가 물컵만 준비해. 물은 내가 알아서 따를게&quot;라고 관리해주는 시스템.&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>Back-End/Java</category>
      <category>개발변태</category>
      <category>라이브러리</category>
      <category>변태</category>
      <category>프레임워크</category>
      <category>하</category>
      <author>슬기로운 개발자</author>
      <guid isPermaLink="true">https://doltae.tistory.com/442</guid>
      <comments>https://doltae.tistory.com/442#entry442comment</comments>
      <pubDate>Tue, 21 Jan 2025 10:01:27 +0900</pubDate>
    </item>
    <item>
      <title>Java Stream(스트림)</title>
      <link>https://doltae.tistory.com/441</link>
      <description>&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;I. Java Stream이란?&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&amp;middot;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;Java 8에서 도입된 기능으로, 컬렉션(Collection) 또는 배열과 같은 데이터 소스의 요소를 처리하고 변환하기 위한&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&amp;nbsp; 선언적이고 함수형 스타일&lt;/b&gt;의 API&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;middot; 스트림을 사용하면 코드가 간결해지고, 데이터 처리 작업을 병렬화하거나 효율적으로 수행할 수 있음.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;1. 선언적 방식&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;middot; 스트림 API는 for 또는 while 루프 대신 선언적으로 데이터를 처리한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; (예: filter, map, collect)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;2. 데이터 프름 중심&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;middot; 스트림은 데이터의 흐름을 처리하기 위해 사용되며 데이터 자체를 변경하지 않는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;middot; 스트림은 원본 데이터를 변경하지 않는 &lt;b&gt;불변성&lt;/b&gt;을 보장한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 style=&quot;color: #333333; text-align: start;&quot; 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;&amp;middot; &lt;b&gt;중간 연산(Intermediate Operation)&lt;/b&gt; : 다른 스트림을 반환하며, 연산은 지연(lazy) 평가된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;middot; &lt;b&gt;종결 연산 (Terminal Operation) :&lt;/b&gt; 스트림을 처리하고 결과를 반환합니다.&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; (예: collect, forEach, count)&lt;/p&gt;
&lt;h4 style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;4. 내부 반복&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;middot; 스트림 API는 개발자가 반복(iteration) 처리를 직접 하지 않고, 스트림 내부에서 반복 처리를 수행한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;5. 병렬 처리&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;middot; 스트림 API는 간단한 코드 변경으로 데이터를 병렬로 처리하는 기능을 제공한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; (예: parallelStream())&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;6. 장점과 주의해야하는 사항.&lt;/b&gt;&lt;/h4&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;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&amp;middot;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;코드 가독성 증가 (함수형 스타일로 작성)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;middot; 데이터 처리 간결화 (필터링, 변환, 수집 등을 단순화)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;middot; 대용량 데이터 처리에 유리 (병렬 스트림)&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;br /&gt;&amp;middot;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;스트림은 한 번만 소비 가능(재사용 불가) &lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;middot; 병렬 스트림 사용 시 공유 자원 처리에 주의&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;middot; 중간 연산은 지연 평가되므로 결과를 보려면 종결 연산이 필요&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;middot; 병렬 스트림은 데이터의 크기와 연산의 복잡성에 따라 성능이 달라질 수 있으므로 신중히 사용.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;middot; 함수형 인터페이스(Predicate, Function)와 람다 표현식의 조합으로 스트림을 활용하면 더욱 유용.&lt;/p&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;II. 스트림 API의 기본 구조&lt;/h2&gt;
&lt;h4 style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;1. 스트림 생성&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&amp;middot;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt; Stream.of(), Arrays.stream(), 컬렉션의 stream() 메서드를 사용하여 생성.&lt;/p&gt;
&lt;h4 style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;2. 중간 연산&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;middot; 데이터 변환 또는 필터링 작업을 수행.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;middot;&lt;b&gt; filter():&lt;/b&gt; 조건에 맞는 요소만 선택.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;middot;&lt;b&gt; map():&lt;/b&gt; 각 요소를 변환.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;middot;&lt;b&gt; sorted():&lt;/b&gt; 요소를 정렬.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;middot; &lt;b&gt;distinct():&lt;/b&gt; 중복 제거.&lt;/p&gt;
&lt;h4 style=&quot;color: #333333; text-align: start;&quot; 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;&amp;middot;&amp;nbsp; 최종 결괄르 도출.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;middot;&lt;b&gt; collect():&lt;/b&gt; 결과를 컬렉션으로 수집.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;middot;&lt;b&gt;&lt;span&gt; &lt;/span&gt;forEach():&lt;/b&gt; 각 요소를 반복 처리.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;middot;&lt;b&gt; reduce():&lt;/b&gt; 모든 요소를 하나의 값으로 합침.&lt;/p&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;III.&lt;span&gt; 예제 코드&lt;/span&gt;&lt;/h2&gt;
&lt;h4 style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;1. 숫자 리스트에서 짝수만 필터링하여 합산.&lt;/b&gt;&lt;/h4&gt;
&lt;pre id=&quot;code_1737519637755&quot; class=&quot;angelscript&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;import java.util.Arrays;
import java.util.List;

public class StreamExample {
    public static void main(String[] args) {
        List&amp;lt;Integer&amp;gt; numbers = Arrays.asList(1, 2, 3, 4, 5, 6);

        int sumOfEvens = numbers.stream() // 스트림 생성
                .filter(n -&amp;gt; n % 2 == 0)  // 중간 연산: 짝수 필터링
                .mapToInt(n -&amp;gt; n)        // 중간 연산: int로 변환
                .sum();                  // 종결 연산: 합산

        System.out.println(&quot;Sum of evens: &quot; + sumOfEvens);
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;h4 style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;2. 문자열 리스트를 대문자로 변환 후 출력.&lt;/b&gt;&lt;/h4&gt;
&lt;pre id=&quot;code_1737519668471&quot; class=&quot;arduino&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;import java.util.Arrays;
import java.util.List;

public class StreamExample2 {
    public static void main(String[] args) {
        List&amp;lt;String&amp;gt; names = Arrays.asList(&quot;Alice&quot;, &quot;Bob&quot;, &quot;Charlie&quot;);

        names.stream()                  // 스트림 생성
                .map(String::toUpperCase) // 중간 연산: 대문자로 변환
                .forEach(System.out::println); // 종결 연산: 출력
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;h4 style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;3. 병렬 스트림 사용&lt;/b&gt;&lt;/h4&gt;
&lt;pre id=&quot;code_1737519693984&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import java.util.stream.IntStream;

public class ParallelStreamExample {
    public static void main(String[] args) {
        IntStream.range(1, 11)       // 1부터 10까지 범위
                .parallel()          // 병렬 스트림 생성
                .forEach(System.out::println);
    }
}&lt;/code&gt;&lt;/pre&gt;</description>
      <category>Back-End/Java</category>
      <category>JDK1.8</category>
      <category>Stream</category>
      <category>스트림</category>
      <author>슬기로운 개발자</author>
      <guid isPermaLink="true">https://doltae.tistory.com/441</guid>
      <comments>https://doltae.tistory.com/441#entry441comment</comments>
      <pubDate>Tue, 21 Jan 2025 09:37:31 +0900</pubDate>
    </item>
  </channel>
</rss>