์๋ก
์คํ๋ง ๋ฐฐ์น(Spring Batch)๋ ๋์ฉ๋ ๋ฐ์ดํฐ๋ฅผ ์ฒ๋ฆฌํ๊ธฐ ์ํ ํ๋ ์์ํฌ๋ก, ์คํ๋ง ํ๋ ์์ํฌ ๊ธฐ๋ฐ์์ ์๋ํฉ๋๋ค. ์ผ๋ฐ์ ์ผ๋ก ๋ฐฐ์น ์์ ์ ๋๋์ ๋ฐ์ดํฐ๋ฅผ ์ฒ๋ฆฌํ๊ฑฐ๋, ์ฃผ๊ธฐ์ ์ด๊ณ ๋ฐ๋ณต์ ์ธ ์์ ์ ์คํํ๋ ๋ฐ ์ฌ์ฉ๋๋ฉฐ, ์คํ๋ง ๋ฐฐ์น๋ ์ด๋ฌํ ์์ ์ ํจ์จ์ ์ด๊ณ ์์ ์ ์ผ๋ก ์ฒ๋ฆฌํ ์ ์๋ ๋ํ์ ์ผ๋ก ์๋์ ๊ฐ์ ๊ธฐ๋ฅ๋ค์ ์ ๊ณตํฉ๋๋ค.
- ๋ก๊น ๋ฐ ์ถ์
- ํธ๋์ญ์ ๊ด๋ฆฌ
- ์์ ์ฒ๋ฆฌ ํต๊ณ
- ์์ ์ฌ์์
- ๊ฑด๋๋ฐ๊ธฐ
- ๋ฆฌ์์ค ๊ด๋ฆฌ
Batch์ Scheduler์ ์ฐจ์ด
๋ฐฐ์น(Batch)๋ ๋ ผ๋ฆฌ์ ๋๋ ๋ฌผ๋ฆฌ์ ์ผ๋ก ๊ด๋ จ๋ ์ผ๋ จ์ ๋ฐ์ดํฐ๋ฅผ ๊ทธ๋ฃนํํ์ฌ ์ผ๊ด ์ฒ๋ฆฌํ๋ ๋ฐฉ๋ฒ์ ์๋ฏธํฉ๋๋ค. ๋ฐ๋ฉด์ ์ค์ผ์ค๋ฌ(Scheduler)๋ ์ฃผ์ด์ง ์์ ์ ๋ฏธ๋ฆฌ ์ ์๋ ์๊ฐ์ ์คํํ ์ ์๊ฒ ํด์ฃผ๋ ๋๊ตฌ๋ ์ํํธ์จ์ด๋ฅผ ์๋ฏธํฉ๋๋ค.
์ฌ๊ธฐ์ ์ฃผ์ํ ์ ์ ๋ฐฐ์น๋ ๋๋์ ๋ฐ์ดํฐ๋ฅผ ์ผ๊ด์ ์ผ๋ก ์ฒ๋ฆฌํ ๋ฟ, ํน์ ์ฃผ๊ธฐ๋ง๋ค ์๋์ผ๋ก ๋์๊ฐ๋ ์ค์ผ์ค๋ง๊ณผ๋ ๊ด๋ จ์ด ์๋ค๋ ๊ฒ์
๋๋ค. Spring Batch๋ ์ค์ผ์ค๋ฌ์ ํจ๊ป ์ฌ์ฉํ ์ ์๋๋ก ์ค๊ณ๋์ด ์์ ๋ฟ์ด์ง ์ค์ผ์ค๋ฌ ์์ฒด๋ฅผ ๋์ฒดํ๋ ๊ฒ์ ์๋๋๋ค. (= ๋ฐฐ์น๋ ๋๋ ์ฒ๋ฆฌ๋ฅผ ์๋ฏธํ๋ ๊ฒ์ด์ง, ์ผ์ ์ฃผ๊ธฐ๋ง๋ค ๋์๊ฐ๋ ๊ฒ์ ์๋ฏธํ์ง ์๋๋ค.) ๋ฐ๋ผ์ ์์
์ค์ผ์ค๋ง ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ธ Quartz ๋ฑ๊ณผ Spring Batch๋ฅผ ๋น๊ตํ๋ ๊ฒ์ ์ ์ ํ์ง ๋ชปํฉ๋๋ค. (https://yeonyeon.tistory.com/310)
Batch ์ฌ์ฉ ์ฌ๋ก
์ผ๋งค์ถ ์ง๊ณ
์ปค๋จธ์ค ์ฌ์ดํธ์์๋ ํ๋ฃจ์ ๊ฑฐ๋๊ฑด์ด 50๋ง์์ 100๋ง ๊ฑด๊น์ง ์ด๋ฃจ์ด์ง ์ ์์ต๋๋ค. ์ด๋ฐ ๊ฒฝ์ฐ ๊ด๋ จ๋ ๋ฐ์ดํฐ๋ ์ต์ 100๋ง์์ 200๋ง ํ ์ด์์ด ๋ ์ ์๋๋ฐ, ํ ๋ฌ ๋์์ ์ด๋ฐ ๋ฐ์ดํฐ๊ฐ 5000๋ง์์ 1์ต๊น์ง ์์ผ ์ ์์ต๋๋ค. ์ด๋ฐ ๋ฐ์ดํฐ๋ฅผ ์ค์๊ฐ์ผ๋ก ์ง๊ณํ๋ ์ฟผ๋ฆฌ๋ฅผ ์คํํ๋ฉด ์กฐํ ์๊ฐ์ด ๊ธธ์ด์ง๊ณ ์๋ฒ์ ๋ง์ ๋ถ๋ด์ด ๊ฐ๊ฒ ๋ฉ๋๋ค. ๊ทธ๋์ ๋งค์ผ ์๋ฒฝ์ ์ ๋ ์ ๋งค์ถ ์ง๊ณ ๋ฐ์ดํฐ๋ฅผ ๋ฏธ๋ฆฌ ์์ฑํด ๋์ด, ์ธ๋ถ์์ ์์ฒญ์ด ์ค๋ฉด ์ ๋ ์ ์ง๊ณํ ๋ฐ์ดํฐ๋ฅผ ์ ๊ณตํ๋ ๋ฐฉ๋ฒ์ผ๋ก ํด๊ฒฐํฉ๋๋ค.
๊ตฌ๋ ์๋น์ค
์ ํด์ง ์๊ฐ์ ๊ตฌ๋ ์๋ค์๊ฒ ๋ฉ์ผ์ ์ผ๊ด ์ ์กํ๋ ๊ฒฝ์ฐ, ๋ฐฐ์น ์ฒ๋ฆฌ๋ฅผ ํ์ฉํ๋ฉด ์๋น์ค ๊ตฌํ์ด ๊ฐ๋จํด์ง๋๋ค. ์ ์กํ ๋ฐ์ดํฐ ๋ด์ญ๊ณผ ๊ตฌ๋ ์ ์ ๋ณด๋ฅผ ํ์ฉํ์ฌ ๊ตฌ๋ ์ ์ ์ฒญํ ํ์๋ค์๊ฒ ๊ท์น์ ์ผ๋ก ๋ฉ์ผ์ ๋ณด๋ผ ์ ์์ต๋๋ค.
๋ฐ์ดํฐ ๋ฐฑ์
๋๊ท๋ชจ ๋ฐ์ดํฐ๋ฒ ์ด์ค๋ฅผ ์ด์ํ๊ฒ ๋๋ฉด, ๋ฐ์ดํฐ์ ์ผ๊ด์ฑ์ ๋ณด์ฅํ๊ธฐ ์ํด ์ฃผ๊ธฐ์ ์ธ ๋ฐ์ดํฐ ๋ฐฑ์ ์ด ํ์์ ์ ๋๋ค. ๊ทธ๋ฌ๋ ์ด๋ฐ ๋ฐฑ์ ์์ ์ ์์คํ ์ ์๋นํ ๋ถ๋ด์ ์ค ์ ์๊ธฐ์ ์ผ๋ฐ์ ์ผ๋ก ์ฌ์ฉ์ ํธ๋ํฝ์ด ์๋์ ์ผ๋ก ์ ์ ์๊ฐ๋์ ๋ฐฐ์น ์ฒ๋ฆฌ ๋ฐฉ์์ ํตํด ๋ฐฑ์ ์์ ์ ์คํํฉ๋๋ค.
Spring Batch์ ์ฉ์ด
์คํ๋ง ๋ฐฐ์น์์ ์ฌ์ฉํ๋ ์ฃผ์ ์ฉ์ด๋ค๊ณผ ์๋ฏธ๋ ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
- Job
- Job์ ์ ์ฒด ๋ฐฐ์น ์ฒ๋ฆฌ ๊ณผ์ ์ ์ถ์ํํ ๊ฐ๋ ์ผ๋ก, ํ๋ ๋๋ ๊ทธ ์ด์์ Step์ ํฌํจํ๋ฉฐ, ์คํ๋ง ๋ฐฐ์น ๊ณ์ธต์์ ๊ฐ์ฅ ์์์ ์์นํฉ๋๋ค.
- ๊ฐ Job์ ๊ณ ์ ํ ์ด๋ฆ์ ๊ฐ์ง๋ฉฐ, ์ด ์ด๋ฆ์ ์คํ์ ํ์ํ ํ๋ผ๋ฏธํฐ์ ํจ๊ป JobInstance๋ฅผ ๊ตฌ๋ณํ๋ ๋ฐ ์ฌ์ฉ๋ฉ๋๋ค.
- JobInstance
- JobInstance๋ ํน์ Job์ ์ค์ ์คํ ์ธ์คํด์ค๋ฅผ ์๋ฏธํฉ๋๋ค. ์๋ฅผ ๋ค์ด, "๋งค์ผ ์์นจ 8์์ ๋ฐ์ดํฐ๋ฅผ ์ฒ๋ฆฌ"ํ๋ Job์ ๊ตฌ์ฑํ๋ค๊ณ ๊ฐ์ ํ๋ฉด, 1์ 1์ผ, 1์ 2์ผ ๋ฑ ๋งค์ผ ์คํ๋ ๋๋ง๋ค ์๋ก์ด JobInstance๊ฐ ์์ฑ๋ฉ๋๋ค.
- ํ๋ฒ ์์ฑ๋ JobInstance๋ ํด๋น ๋ ์ง์ ๋ฐ์ดํฐ๋ฅผ ์ฒ๋ฆฌํ๋ ๋ฐ ์ฌ์ฉ๋๋ฉฐ, ์คํจํ์ ๊ฒฝ์ฐ ๊ฐ์ JobInstance๋ฅผ ๋ค์ ์คํํ์ฌ ์์ ์ ์๋ฃํ ์ ์์ต๋๋ค.
- JobParameters
- JobParameters๋ JobInstance๋ฅผ ์์ฑํ๊ณ ๊ตฌ๋ณํ๋ ๋ฐ ์ฌ์ฉ๋๋ ํ๋ผ๋ฏธํฐ์ ๋๋ค.
- Job์ด ์คํ๋ ๋ ํ์ํ ํ๋ผ๋ฏธํฐ๋ฅผ ๊ณตํ๋ฉฐ, JobInstance๋ฅผ ๊ตฌ๋ณํ๋ ์ญํ ๋ ํฉ๋๋ค.
- ์คํ๋ง ๋ฐฐ์น๋ String, Double, Long, Date ์ด๋ ๊ฒ 4๊ฐ์ง ํ์ ์ ํ๋ผ๋ฏธํฐ๋ฅผ ์ง์ํฉ๋๋ค.
- JobExecution
- JobExecution์ JobInstance์ ํ ๋ฒ์ ์ํ ์๋๋ฅผ ๋ํ๋ ๋๋ค.
- ์๋ฅผ ๋ค์ด, 1์ 1์ผ์ ์คํ๋ JobInstance๊ฐ ์คํจํ์ ๋ ์ฌ์๋ํ๋ฉด, ๊ฐ์ JobInstance์ ๋ํ ์๋ก์ด JobExcecution์ด ์์ฑ๋ฉ๋๋ค.
- JobExecution์ ์คํ ์ํ, ์์์๊ฐ, ์ข ๋ฃ์๊ฐ, ์์ฑ์๊ฐ ๋ฑ JobInstance์ ์คํ์ ๋ํ ์ธ๋ถ ์ ๋ณด๋ฅผ ๋ด๊ณ ์์ต๋๋ค.
- Step
- Step์ Job์ ํ์ ๋จ๊ณ๋ก์ ์ค์ ๋ฐฐ์น ์ฒ๋ฆฌ ์์ ์ด ์ด๋ฃจ์ด์ง๋ ๋จ์์ ๋๋ค.
- ํ ๊ฐ ์ด์์ Step์ผ๋ก Job์ด ๊ตฌ์ฑ๋๋ฉฐ, ๊ฐ Step์ ์์ฐจ์ ์ผ๋ก ์ฒ๋ฆฌ๋ฉ๋๋ค.
- ๊ฐ Step ๋ด๋ถ์์๋ ItemReader, ItemProcessor, ItemWriter๋ฅผ ์ฌ์ฉํ๋ chunk ๋ฐฉ์ ๋๋ Tasklet ํ๋๋ฅผ ๊ฐ์ง ์ ์์ต๋๋ค.
- StepExecution
- StepExecution์ Step์ ํ ๋ฒ์ ์คํ์ ๋ํ๋ด๋ฉฐ, Step์ ์คํ ์ํ, ์คํ ์๊ฐ ๋ฑ์ ์ ๋ณด๋ฅผ ํฌํจํฉ๋๋ค.
- JobExecution๊ณผ ์ ์ฌํ๊ฒ, ๊ฐ Step์ ์คํ ์๋๋ง๋ค ์๋ก์ด StepExecution์ด ์์ฑ๋ฉ๋๋ค.
- ๋ํ, ์ฝ์ ์์ดํ ์ ์, ์ด ์์ดํ ์ ์, ์ปค๋ฐ ํ์, ์คํตํ ์์ดํ ์ ์ ๋ฑ์ Step ์คํ์ ๋ํ ์์ธ ์ ๋ณด๋ ํฌํฉ ํฉ๋๋ค.
- ExecutionContext
- ExecutionContext๋ Step ๊ฐ ๋๋ Job ์คํ ๋์ค ๋ฐ์ดํฐ๋ฅผ ๊ณต์ ํ๋ ๋ฐ ์ฌ์ฉ๋๋ ์ ์ฅ์์ ๋๋ค.
- JobExecutionContext์ StepExecutionContext ๋ ์ข ๋ฅ๊ฐ ์์ผ๋ฉฐ, ๋ฒ์์ ์ ์ฅ ์์ ์ ๋ฐ๋ผ ์ ์ ํ๊ฒ ์ฌ์ฉ๋ฉ๋๋ค.
- Job์ด๋ Step์ด ์คํจํ์ ๊ฒฝ์ฐ, ExecutionContext๋ฅผ ํตํด ๋ง์ง๋ง ์คํ ์ํ๋ฅผ ์ฌ๊ตฌ์ฑํ์ฌ ์ฌ์๋ ๋๋ ๋ณต๊ตฌ ์์ ์ ์ํํ ์ ์์ต๋๋ค.
- JobRepository
- JobRepository๋ ๋ฐฐ์น ์์ ์ ๊ด๋ จ๋ ๋ชจ๋ ์ ๋ณด๋ฅผ ์ ์ฅํ๊ณ ๊ด๋ฆฌํ๋ ๋ฉ์ปค๋์ฆ์ ๋๋ค.
- Job ์คํ์ ๋ณด(JobExecution), Step ์คํ์ ๋ณด(StepExecution), Job ํ๋ผ๋ฏธํฐ(JobParameters)๋ฑ์ ์ ์ฅํ๊ณ ๊ด๋ฆฌํฉ๋๋ค.
- Job์ด ์คํ๋ ๋, JobRepository๋ ์๋ก์ด JobExecution๊ณผ StepExecution์ ์์ฑํ๊ณ , ์ด๋ฅผ ํตํด ์คํ ์ํ๋ฅผ ์ถ์ ํฉ๋๋ค.
- JobLauncher
- JobLauncher๋ Job๊ณผ JobParameters๋ฅผ ๋ฐ์ Job์ ์คํํ๋ ์ญํ ์ ํฉ๋๋ค.
- ์ด๋ ์ ๋ฐ์ ์ธ Job์ ์๋ช ์ฃผ๊ธฐ๋ฅผ ๊ด๋ฆฌํ๋ฉฐ, JobRepository๋ฅผ ํตํด ์คํ ์ํ๋ฅผ ์ ์งํฉ๋๋ค.
- ItemReader
- ItemReader๋ ๋ฐฐ์น ์์ ์์ ์ฒ๋ฆฌํ ์์ดํ ์ ์ฝ์ด์ค๋ ์ญํ ์ ํฉ๋๋ค.
- ์ฌ๋ฌ ํ์์ ๋ฐ์ดํฐ ์์ค(์: ๋ฐ์ดํฐ๋ฒ ์ด์ค, ํ์ผ, ๋ฉ์์ง ํ ๋ฑ)๋ก ๋ถํฐ ๋ฐ์ดํฐ๋ฅผ ์ฝ์ด์ค๋ ๋ค์ํ ItemReader ๊ตฌํ์ฒด๊ฐ ์ ๊ณต๋ฉ๋๋ค.
- ItemProcessor
- ItemProcessor๋ ItemReader๋ก๋ถํฐ ์ฝ์ด์จ ์์ดํ ์ ์ฒ๋ฆฌํ๋ ์ญํ ์ ํฉ๋๋ค.
- ์ด๋ ์ ํ์ ์ธ ๋ถ๋ถ์ผ๋ก์, ํ์์ ๋ฐ๋ผ ์ฌ์ฉํ ์ ์์ผ๋ฉฐ, ๋ฐ์ดํฐ ํํฐ๋ง, ๋ณํ ๋ฑ์ ์์ ์ ์ํํ ์ ์์ต๋๋ค.
- ItemWriter
- ItemWriter๋ ItemProcessor์์ ์ฒ๋ฆฌ๋ ๋ฐ์ดํฐ๋ฅผ ์ต์ข ์ ์ผ๋ก ๊ธฐ๋กํ๋ ์ญํ ์ ํฉ๋๋ค.
- ItemWriter ์ญ์ ๋ค์ํ ํํ์ ๊ตฌํ์ฒด๋ฅผ ํตํด ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ๊ธฐ๋กํ๊ฑฐ๋, ํ์ผ์ ์์ฑํ๊ฑฐ๋ ๋ฉ์์ง๋ฅผ ๋ฐํํ๋ ๋ฑ ๋ค์ํ ๋ฐฉ์์ผ๋ก ๋ฐ์ดํฐ๋ฅผ ์ธ ์ ์์ต๋๋ค.
- Tasklet
- Tasklet์ ๊ฐ๋จํ ๋จ์ผ ์์ , ์๋ฅผ ๋ค์ด ๋ฆฌ์์ค์ ์ ๋ฆฌ ๋๋ ์์คํ ์ํ์ ์ฒดํฌ ๋ฑ์ ์ํํ ๋ ์ฌ์ฉ๋ฉ๋๋ค.
- ์ด๋ ์คํ๋ง ๋ฐฐ์น์ Step ๋ด์์ ๋จ์ผ ์์ ์ ์ํํ๊ธฐ ์ํ ์ธํฐํ์ด์ค๋ก, ์ผ๋ฐ์ ์ผ๋ก ItemReader, ItemProcessor, ItemWriter์ ๋ฌถ์์ ๊ฐ์ง๋ Chunk ๊ธฐ๋ฐ ์ฒ๋ฆฌ ๋ฐฉ์๊ณผ๋ ๋ค๋ฆ ๋๋ค.
- Tasklet์ execute ๋ฉ์๋๋ Step์ ๋ชจ๋ ์ฒ๋ฆฌ๊ฐ ๋๋ ๋๊น์ง ๊ณ์ ํธ์ถ๋ฉ๋๋ค.
- JobOperator
- JobOperator๋ ์ธ๋ถ ์ธํฐํ์ด์ค๋ก, Job์ ์คํ๊ณผ ์ค์ง, ์ฌ์์ ๋ฑ์ ๋ฐฐ์น ์์ ํ๋ฆ์ ์ด๋ฅผ ๋ด๋นํฉ๋๋ค.
- ์ด ์ธํฐํ์ด์ค๋ฅผ ํตํด JobLauncher์ JobRepository์ ๋ํ ์ง์ ์ ์ธ ์ ๊ทผ ์์ด๋ ๋ฐฐ์น ์์ ์ ์ํํ๊ณ ์ํ๋ฅผ ์กฐํํ ์ ์์ต๋๋ค.
- JobExplorer
- JobExplorer๋ Job์ ์คํ ์ด๋ ฅ์ ์กฐํํ๋ ๋ฐ ์ฌ์ฉ๋ฉ๋๋ค.
- JobRepository์์ ์ ๊ณตํ๋ ์ ๋ณด์ ์ ์ฌํ์ง๋ง, JobRepository๋ ์ฃผ๋ก Job์ ์คํ ๋์ค์ธ ์ํ์ ๋ํด ์ ๋ฐ์ดํธํ๊ณ ๊ด๋ฆฌํ๋ ๋ฐ๋ฉด, JobExplorer๋ ์ฃผ๋ก ์ฝ๊ธฐ ์ ์ฉ ์ ๊ทผ์ ์ด์ ์ ๋ง์ถ๊ณ ์์ต๋๋ค.
๋ฉํ ํ ์ด๋ธ
๋จผ์ ์คํ๋ง ๋ฐฐ์น๋ ๋ฐฐ์น ์์ ์ ์ํ๋ฅผ ๊ด๋ฆฌํ๊ธฐ ์ํ ๋ฉํ ๋ฐ์ดํฐ๋ฅผ ์ ์ฅํ๋ ์๋ 6๊ฐ์ ํ ์ด๋ธ๋ค์ ์๋์ผ๋ก ์์ฑํฉ๋๋ค. ๋ํ ๋ฐฐ์น ์์ ์ ์ํํ๋ฉด ์๋์ผ๋ก ์์ฑ๋ ํ ์ด๋ธ๋ค์ ์ปฌ๋ผ ๊ฐ๋ค์ด ์ฑ์์ง๋๋ค.
1. BATCH_JOB_INSTANCE
CREATE TABLE BATCH_JOB_INSTANCE (
JOB_INSTANCE_ID BIGINT PRIMARY KEY ,
VERSION BIGINT,
JOB_NAME VARCHAR(100) NOT NULL ,
JOB_KEY VARCHAR(32) NOT NULL
);
BATCH_JOB_INSTANCE ํ ์ด๋ธ์ JobInstance์ ๊ด๋ จ๋ ๋ชจ๋ ์ ๋ณด๋ฅผ ๊ฐ์ง๋ฉฐ, ์ ์ฒด ๊ณ์ธต ๊ตฌ์กฐ์ ์ต์์ ์ญํ ์ ํฉ๋๋ค.
- JOB_INSTANCE_ID: ์คํ๋ JobInstance์ ID
- VERSION: ๋ฐฐ์น ํ ์ด๋ธ์ ๋๊ด์ ๋ฝ ์ ๋ต์ ์ํด ์ฌ์ฉ๋๋ ๊ฐ
- JOB_NAME: ์คํ๋ Job์ ์ด๋ฆ์ผ๋ก, null์ด ์๋ ์ฌ์ผํจ
- JOB_KEY: JobParameter๋ก ์์ฑ๋ JobInstance์ ํค(Job ์ค๋ณต ์ํ ์ฒดํฌ๋ฅผ ์ํ ๊ณ ์ ํค)
2. BATCH_JOB_EXECUTION
CREATE TABLE BATCH_JOB_EXECUTION (
JOB_EXECUTION_ID BIGINT PRIMARY KEY ,
VERSION BIGINT,
JOB_INSTANCE_ID BIGINT NOT NULL,
CREATE_TIME TIMESTAMP NOT NULL,
START_TIME TIMESTAMP DEFAULT NULL,
END_TIME TIMESTAMP DEFAULT NULL,
STATUS VARCHAR(10),
EXIT_CODE VARCHAR(20),
EXIT_MESSAGE VARCHAR(2500),
LAST_UPDATED TIMESTAMP,
constraint JOB_INSTANCE_EXECUTION_FK foreign key (JOB_INSTANCE_ID)
references BATCH_JOB_INSTANCE(JOB_INSTANCE_ID)
) ;
BATCH_JOB_EXECUTION ํ ์ด๋ธ์ JobExecution์ ๊ด๋ จ๋ ๋ชจ๋ ์ ๋ณด๊ฐ ๋ค์ด์์ต๋๋ค. JobExcution์ JobInstance๊ฐ ์คํ๋ ๋๋ง๋ค ์์์๊ฐ, ์ข ๋ฃ์๊ฐ, ์ข ๋ฃ์ฝ๋ ๋ฑ ๋ค์ํ ์ ๋ณด๋ฅผ ๊ฐ์ง๊ณ ์์ต๋๋ค.
- JOB_EXECUTION_ID: ์คํ๋ JobExecution์ ID
- VERSION: ๋ฐฐ์น ํ ์ด๋ธ์ ๋๊ด์ ๋ฝ ์ ๋ต์ ์ํด ์ฌ์ฉ๋๋ ๊ฐ
- JOB_INSTANCE_ID: BATCH_JOB_INSTANCE ํ ์ด๋ธ์ ์ธ๋ ํค
- CREATE_TIME: JobExecution์ด ์์ฑ๋ ์๊ฐ
- START_TIME: JobExecution์ด ์คํ๋ ์๊ฐ
- END_TIME: JobExecution์ด ์ข ๋ฃ๋ ์๊ฐ(์ฑ๊ณต๊ณผ ์คํจ ์ฌ๋ถ์ ์๊ด์์ด ์คํ์ด ์๋ฃ๋ ์๊ฐ์ ์๋ฏธ)
- STATUS: JobExecution์ ์ํ(BatchStatus์ Enum ํ์ )
- EXIT_CODE: JobExecution์ ์ข ๋ฃ ์ฝ๋
- EXIT_MESSAGE: JobExecution์ ์ข ๋ฃ ๋ฉ์์ง. ์๋ฌ๊ฐ ๋ฐ์ํ ๊ฒฝ์ฐ ์๋ฌ๋ฉ์์ง
- LAST_UPDATED: JobExcution์ด ์์ ๋ ์๊ฐ
3. BATCH_JOB_EXECUTION_PARAMS
CREATE TABLE BATCH_JOB_EXECUTION_PARAMS (
JOB_EXECUTION_ID BIGINT NOT NULL ,
PARAMETER_NAME VARCHAR(100) NOT NULL ,
PARAMETER_TYPE VARCHAR(100) NOT NULL ,
PARAMETER_VALUE VARCHAR(2500) ,
IDENTIFYING CHAR(1) NOT NULL ,
constraint JOB_EXEC_PARAMS_FK foreign key (JOB_EXECUTION_ID)
references BATCH_JOB_EXECUTION(JOB_EXECUTION_ID)
);
BATCH_JOB_EXECUTION_PARAMS ํ ์ด๋ธ์ JobParameters์ ๊ด๋ จ๋ ๋ชจ๋ ์ ๋ณด๊ฐ ๋ค์ด์์ต๋๋ค.
- JOB_EXECUTION_ID: ์คํ๋ JobExecution์ ID(BATCH_JOB_EXECUTION ํ ์ด๋ธ์ ์ธ๋ ํค)
- TYPE_CD: JobPameter์ ํ์ ์ฝ๋(string, date, long, double)
- KEY_NAME: JobPameter์ ์ด๋ฆ
- STRING_VAL: JobPameter์ String๊ฐ(TYPE_CD๊ฐ String์ผ ๋ ๊ฐ์ด ์กด์ฌ)
- DATETIME: JobPameter์ Date๊ฐ(TYPE_CD๊ฐ Date ์ผ ๋ ๊ฐ์ด ์กด์ฌ)
- LONG_VAL: JobPameter์ Long๊ฐ. (TYPE_CD๊ฐ Long์ผ ๋ ๊ฐ์ด ์กด์ฌ)
- DOUBLE_VAL: JobPameter์ Double๊ฐ. (TYPE_CD๊ฐ Double์ผ ๋ ๊ฐ์ด ์กด์ฌ)
- IDENTIFYING: JobInstance์ ํค์ ์์ฑ์ ํฌํจ๋์๋์ง ์ฌ๋ถ
4. BATCH_JOB_EXECUTION_CONTEXT
CREATE TABLE BATCH_JOB_EXECUTION_CONTEXT (
JOB_EXECUTION_ID BIGINT PRIMARY KEY,
SHORT_CONTEXT VARCHAR(2500) NOT NULL,
SERIALIZED_CONTEXT CLOB,
constraint JOB_EXEC_CTX_FK foreign key (JOB_EXECUTION_ID)
references BATCH_JOB_EXECUTION(JOB_EXECUTION_ID)
) ;
BATCH_JOB_EXECUTION_CONTEXT ํ ์ด๋ธ์ ์์ ์ ์คํ ์ปจํ ์คํธ์ ๊ด๋ จ๋ ๋ชจ๋ ์ ๋ณด๊ฐ ๋ค์ด์์ต๋๋ค. ๊ฐ JobExecution๋ง๋ค ์ ํํ ํ๋์ JobExecutionContext๊ฐ ์์ต๋๋ค. ์ด ExecutionContext ๋ฐ์ดํฐ๋ ์ผ๋ฐ์ ์ผ๋ก JobInstance๊ฐ ์คํจ ์ ์ค๋จ๋ ์์น์์ ๋ค์ ์์ํ ์ ์๋ ์ ๋ณด๋ฅผ ์ ์ฅํ๊ณ ์์ต๋๋ค.
- JOB_EXECUTION_ID: ์คํ๋ JobExecution์ ID
- SHORT_CONTEXT: ๋ฌธ์์ด๋ก ์ ์ฅ๋ JobExecutionContext ์ ๋ณด
- SERIALIZED_CONTEXT: ์ง๋ ฌํํ์ฌ ์ ์ฅ๋ JobExecutionContext ์ ๋ณด
5. BATCH_STEP_EXECUTION
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,
CREATE_TIME TIMESTAMP NOT NULL,
START_TIME TIMESTAMP DEFAULT NULL ,
END_TIME TIMESTAMP 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(20) ,
EXIT_MESSAGE VARCHAR(2500) ,
LAST_UPDATED TIMESTAMP,
constraint JOB_EXECUTION_STEP_FK foreign key (JOB_EXECUTION_ID)
references BATCH_JOB_EXECUTION(JOB_EXECUTION_ID)
) ;
BATCH_STEP_EXECUTION ํ ์ด๋ธ์ StepExecution ๊ฐ์ฒด์ ๊ด๋ จ๋ ๋ชจ๋ ์ ๋ณด๊ฐ ์ ์ฅ๋ฉ๋๋ค. BATCH_JOB_EXECUTION ํ ์ด๋ธ๊ณผ ์ ์ฌํ๋ฉฐ, ์์ฑ๋ ๊ฐ JobExecution์ ๋ํด ํญ์ ๋จ๊ณ๋น ํ๋ ์ด์์ ํญ๋ชฉ์ด ์กด์ฌํฉ๋๋ค. STEP์ EXECUTION ์ ๋ณด์ธ ์ฝ์ ์, ์ปค๋ฐ ์, ์คํต ์ ๋ฑ ๋ค์ํ ์ ๋ณด๋ฅผ ์ถ๊ฐ๋ก ๋ด๊ณ ์์ต๋๋ค.
- STEP_EXECUTION_ID: ์คํ๋ StepExecution์ ID
- VERSION: ๋ฐฐ์น ํ ์ด๋ธ์ ๋๊ด์ ๋ฝ ์ ๋ต์ ์ํด ์ฌ์ฉ๋๋ ๊ฐ
- STEP_NAME: ์คํ๋ StepExecution์ Step ์ด๋ฆ
- JOB_EXECUTION_ID: ์คํ๋ JobExecution์ ID
- START_TIME: StepExecution์ด ์์๋ ์๊ฐ
- END_TIME: StepExecution์ด ์ข ๋ฃ๋ ์๊ฐ(์ฑ๊ณต๊ณผ ์คํจ ์ฌ๋ถ์ ์๊ด์์ด ์คํ์ด ์๋ฃ๋ ์๊ฐ์ ์๋ฏธ)
- STATUS: StepExecution์ ์ํ(BatchStatus์ Enum ํ์ )
- COMMIT_COUNT: StepExecution ์คํ ์ค, ์ปค๋ฐํ ํ์
- READ_COUNT: StepExecution ์คํ ์ค, ์ฝ์ ๋ฐ์ดํฐ ์
- FILTER_COUNT: StepExecution ์คํ ์ค, ํํฐ๋ง๋ ๋ฐ์ดํฐ ์
- WRITE_COUNT: StepExecution ์คํ ์ค, ์์ฑ ๋ฐ ์ปค๋ฐ๋ ๋ฐ์ดํฐ ์
- READ_SKIP_COUNT: StepExecution ์คํ ์ค, ์ฝ๊ธฐ๋ฅผ ์คํตํ ๋ฐ์ดํฐ ์
- WRITE_SKIP_COUNT: StepExecution ์คํ ์ค, ์์ฑ์ ์คํตํ ๋ฐ์ดํฐ ์
- PROCESS_SKIP_COUNT: StepExecution ์คํ ์ค, ์ฒ๋ฆฌ๋ฅผ ์คํตํ ๋ฐ์ดํฐ ์
- EXIT_CODE: StepExecution์ ์ข ๋ฃ ์ฝ๋
- ROLLBACK_COUNT: StepExecution ์คํ ์ค, ๋กค๋ฐฑ ํ์
- EXIT_MESSAGE: StepExecution์ ์ข ๋ฃ ๋ฉ์์ง. ์๋ฌ๊ฐ ๋ฐ์ํ ๊ฒฝ์ฐ ์๋ฌ๋ฉ์์ง
- LAST_UPDATED: StepExecution์ด ์์ ๋ ์๊ฐ
6. BATCH_STEP_EXECUTION_CONTEXT
CREATE TABLE BATCH_JOB_EXECUTION_CONTEXT (
JOB_EXECUTION_ID BIGINT PRIMARY KEY,
SHORT_CONTEXT VARCHAR(2500) NOT NULL,
SERIALIZED_CONTEXT CLOB,
constraint JOB_EXEC_CTX_FK foreign key (JOB_EXECUTION_ID)
references BATCH_JOB_EXECUTION(JOB_EXECUTION_ID)
) ;
BATCH_STEP_EXECUTION_CONTEXT ํ ์ด๋ธ์ StepExecutionContext์ ๊ด๋ จ๋ ๋ชจ๋ ์ ๋ณด๊ฐ ์ ์ฅ๋๋ฉฐ, ์คํ ์คํ๋น ์ ํํ ํ๋์ ExecutionContext๊ฐ ์์ผ๋ฉฐ, ํน์ ์คํ ์คํ์ ์ํด ์ ์ง๋์ด์ผ ํ๋ ๋ชจ๋ ๋ฐ์ดํฐ๊ฐ ํฌํจ๋์ด ์์ต๋๋ค. ์ด ExecutionContext ๋ฐ์ดํฐ๋ ์ผ๋ฐ์ ์ผ๋ก JobInstance๊ฐ ์คํจ ์ ์ค๋จ๋ ์์น์์ ๋ค์ ์์ํ ์ ์๋ ์ ๋ณด๋ฅผ ์ ์ฅํ๊ณ ์์ต๋๋ค.
- STEP_EXECUTION_ID: ์คํ๋ StepExecution์ ID
- SHORT_CONTEXT: ๋ฌธ์์ด๋ก ์ ์ฅ๋ StepExecutionContext ์ ๋ณด
- SERIALIZED_CONTEXT: ์ง๋ ฌํํ์ฌ ์ ์ฅ๋ StepExecutionContext ์ ๋ณด
๊ฐ ๋ฉํ ํ
์ด๋ธ๋ค์ ๊ฐ์ด ๋ค์ด๊ฐ๋ ๊ฒ์ ํ์ธํด๋ณด๊ณ ์ถ์ผ์ ๋ถ์ https://jojoldu.tistory.com/326๋ฅผ ์ฐธ๊ณ ํ๋ฉด ์ข์ ๊ฒ ๊ฐ์ต๋๋ค.
Spring Batch ์ฌ์ฉํ๊ธฐ
Spring Batch์์ ๊ฐ Job์ ์ฌ๋ฌ Step์ ๋ชจ์์ผ๋ก ๊ตฌ์ฑ๋๋ฉฐ, ๊ฐ Step์ ํน์ ํ ๋น์ฆ๋์ค ๋ก์ง ์ฒ๋ฆฌ ๋จ์๋ฅผ ๋ํ๋ ๋๋ค.
1. ๋จ์ผ Step ๊ตฌ์ฑํ๊ธฐ
@Slf4j
@Configuration
@EnableBatchProcessing
public class SimpleJobConfig {
private final JobBuilderFactory jobBuilderFactory;
private final StepBuilderFactory stepBuilderFactory;
@Autowired
public SimpleJobConfig(JobBuilderFactory jobBuilderFactory, StepBuilderFactory stepBuilderFactory) {
this.jobBuilderFactory = jobBuilderFactory;
this.stepBuilderFactory = stepBuilderFactory;
}
@Bean
public Job exampleJob() {
return jobBuilderFactory.get("exampleJob")
.start(step())
.build();
}
@Bean
public Step step() {
return stepBuilderFactory.get("step")
.tasklet((contribution, chunkContext) -> {
log.info("Performing step!");
return RepeatStatus.FINISHED;
})
.build();
}
}
์ ์ฝ๋์์๋ JobBuilderFactory์ StepBuilderFactory๋ฅผ ์ฌ์ฉํ์ฌ Job๊ณผ Step์ ์์ฑํฉ๋๋ค. exampleJob์ด๋ผ๋ Job์ ๋จ์ผ step๋ง์ ํฌํจํ๋ฉฐ, ์ด step์์๋ tasklet์ ํตํด ํน์ ํ ๋์์ ์ํํฉ๋๋ค. ๊ทธ๋ฆฌ๊ณ RepeatStatus.FINISHED๋ฅผ ๋ฐํํ์ฌ ์์ ์ด ์ฑ๊ณต์ ์ผ๋ก ์๋ฃ๋์์์ ๋ํ๋ ๋๋ค.
2. ๋ค์ค Step ๊ตฌ์ฑํ๊ธฐ
์ ์ด๋ฏธ์ง์ฒ๋ผ Step์ ์์ฐจ์ ์ผ๋ก ์คํํ ์ ์์ต๋๋ค.
@Slf4j
@Configuration
@EnableBatchProcessing
public class MultiStepJobConfig {
private final JobBuilderFactory jobBuilderFactory;
private final StepBuilderFactory stepBuilderFactory;
@Autowired
public MultiStepJobConfig(JobBuilderFactory jobBuilderFactory, StepBuilderFactory stepBuilderFactory) {
this.jobBuilderFactory = jobBuilderFactory;
this.stepBuilderFactory = stepBuilderFactory;
}
@Bean
public Job exampleJob() {
return jobBuilderFactory.get("exampleJob")
.start(startStep())
.next(nextStep())
.next(lastStep())
.build();
}
@Bean
public Step startStep() {
return stepBuilderFactory.get("startStep")
.tasklet((contribution, chunkContext) -> {
log.info("Start Step!");
return RepeatStatus.FINISHED;
})
.build();
}
@Bean
public Step nextStep() {
return stepBuilderFactory.get("nextStep")
.tasklet((contribution, chunkContext) -> {
log.info("Next Step!");
return RepeatStatus.FINISHED;
})
.build();
}
@Bean
public Step lastStep() {
return stepBuilderFactory.get("lastStep")
.tasklet((contribution, chunkContext) -> {
log.info("Last Step!!");
return RepeatStatus.FINISHED;
})
.build();
}
}
exampleJob์ด๋ผ๋ Job์ startStep, nextStep, lastStep์ ์ธ ๊ฐ์ Step์ ์์ฐจ์ ์ผ๋ก ์ํํฉ๋๋ค. start() ๋ฉ์๋๋ก ์ต์ด ์คํ๋ Step์ ์ค์ ํ๊ณ , next() ๋ฉ์๋๋ก ๊ทธ๋ค์์ ์ํ๋ Step์ ์ฐ๊ฒฐํฉ๋๋ค.
3. Flow๋ฅผ ํตํ Step ๊ตฌ์ฑํ๊ธฐ
์ ์ด๋ฏธ์ง์ฒ๋ผ ์ด์ Step์ ์ฑ๊ณต ์ฌ๋ถ์ ๋ฐ๋ผ ๋ถ๊ธฐ์ฒ๋ฆฌ๋ฅผ ํ ์ ์์ต๋๋ค.
@Slf4j
@Configuration
@EnableBatchProcessing
public class FlowJobConfig {
private final JobBuilderFactory jobBuilderFactory;
private final StepBuilderFactory stepBuilderFactory;
@Autowired
public FlowJobConfig(JobBuilderFactory jobBuilderFactory, StepBuilderFactory stepBuilderFactory) {
this.jobBuilderFactory = jobBuilderFactory;
this.stepBuilderFactory = stepBuilderFactory;
}
@Bean
public Job exampleJob() {
// Job ์์ฑ
return jobBuilderFactory.get("exampleJob")
.start(startStep())
.on(ExitStatus.FAILED.getExitCode()) // startStep์ ExitStatus๊ฐ FAILED์ผ ๊ฒฝ์ฐ
.to(failOverStep()) // failOver Step์ ์คํ ์ํจ๋ค.
.on("*") // failOver Step์ ๊ฒฐ๊ณผ์ ์๊ด์์ด
.to(writeStep()) // write Step์ ์คํ ์ํจ๋ค.
.end() // Flow๋ฅผ ์ข
๋ฃ์ํจ๋ค.
.from(startStep()) // startStep์ด FAILED๊ฐ ์๋๊ณ COMPLETED์ผ ๊ฒฝ์ฐ
.on(ExitStatus.COMPLETED.getExitCode())
.to(processStep()) // process Step์ ์คํ ์ํจ๋ค
.on("*") // process Step์ ๊ฒฐ๊ณผ์ ์๊ด์์ด
.to(writeStep()) // write Step์ ์คํ ์ํจ๋ค.
.end() // Flow๋ฅผ ์ข
๋ฃ ์ํจ๋ค.
.from(startStep()) // startStep์ ๊ฒฐ๊ณผ๊ฐ FAILED, COMPLETED๊ฐ ์๋ ๋ชจ๋ ๊ฒฝ์ฐ
.on("*")
.to(writeStep()) // write Step์ ์คํ์ํจ๋ค.
.on("*") // write Step์ ๊ฒฐ๊ณผ์ ์๊ด์์ด
.end() // Flow๋ฅผ ์ข
๋ฃ์ํจ๋ค.
.end()
.build();
}
@Bean
public Step startStep() {
// ์ฒซ๋ฒ์งธ Step ์์ฑ
return stepBuilderFactory.get("startStep")
.tasklet((contribution, chunkContext) -> {
log.info("Start Step!");
String result = "COMPLETED";
// String result = "FAIL";
// String result = "UNKNOWN";
// Flow์์ on์ RepeatStatus๊ฐ ์๋ ExitStatus๋ฅผ ๋ฐ๋ผ๋ณธ๋ค.
if ("COMPLETED".equals(result))
contribution.setExitStatus(ExitStatus.COMPLETED);
else if ("FAIL".equals(result))
contribution.setExitStatus(ExitStatus.FAILED);
else if ("UNKNOWN".equals(result))
contribution.setExitStatus(ExitStatus.UNKNOWN);
return RepeatStatus.FINISHED;
})
.build();
}
@Bean
public Step failOverStep() {
// ์คํจ ์ ์ํํ Step ์์ฑ
return stepBuilderFactory.get("failOverStep")
.tasklet((contribution, chunkContext) -> {
log.info("FailOver Step!");
return RepeatStatus.FINISHED;
})
.build();
}
@Bean
public Step processStep() {
// ์ฒ๋ฆฌ๋ฅผ ์ํ Step ์์ฑ
return stepBuilderFactory.get("processStep")
.tasklet((contribution, chunkContext) -> {
log.info("Process Step!");
return RepeatStatus.FINISHED;
})
.build();
}
@Bean
public Step writeStep() {
// ๊ฒฐ๊ณผ๋ฅผ ๊ธฐ๋กํ๊ธฐ ์ํ Step ์์ฑ
return stepBuilderFactory.get("writeStep")
.tasklet((contribution, chunkContext) -> {
log.info("Write Step!");
return RepeatStatus.FINISHED;
})
.build();
}
}
์ ์ฝ๋์์๋ ๋ค์๊ณผ ๊ฐ์ ๊ตฌ์กฐ๋ฅผ ๊ฐ์ง Job์ ์ ์ํ๊ณ ์์ต๋๋ค.
- startStep(): ์์ Step์ ์ ์ํ๊ณ ์์ต๋๋ค. ExitStatus๋ฅผ COMPLETED, FAILED, UNKNOWN ์ค ํ๋๋ก ์ค์ ํ์ฌ ๋ค์ Step์ ์ํ์ ์ ์ดํฉ๋๋ค.
- failOverStep(): startStep()์ ExitStatus๊ฐ FAILED์ผ ๊ฒฝ์ฐ ์ํ๋ Step์ ๋๋ค.
- processStep(): startStep()์ ExitStatus๊ฐ COMPLETED์ผ ๊ฒฝ์ฐ ์ํ๋ Step์ ๋๋ค.
- writeStep(): ์์ ๋ชจ๋ ์ํฉ ํ์ ์ํ๋ Step์ ๋๋ค.
๊ฐ Step์ Tasklet์ ํตํด ์ค์ ์ํ๋ ๋ก์ง์ ์ ์ํ๊ณ ์์ผ๋ฉฐ, on() ๋ฉ์๋๋ฅผ ํตํด ExitStatus์ ๋ฐ๋ผ ์ํ๋ Step์ ์ง์ ํ๊ณ end()๋ฅผ ํตํด Flow๋ฅผ ์ข
๋ฃํฉ๋๋ค.
STEP์ ๊ตฌ์ฑํ๋ Tasklet๊ณผ Chunk ์งํฅ ์ฒ๋ฆฌ
Job์ Step๋ค์ ์์ฐจ์ ์ผ๋ก ์ํํ๊ฒ ๋๋๋ฐ, Step์ ์ฃผ๋ก Tasklet ๋ฐฉ์๊ณผ chunk ๋ฐฉ์์ด ์กด์ฌํฉ๋๋ค.
* Tasklet ๋ฐฉ์
Tasklet์ ๊ธฐ๋ณธ์ ์ผ๋ก ํ๋์ ์์ ์ ์ํํ๋ ๋ฐฉ์์ ๋๋ค. ๋์ฒด๋ก ๋จ์ํ๊ฑฐ๋ ๋ณต์กํ์ง ์์ ์์ ์ ์ํํ๋ ๋ฐ ์ ํฉํ๋ฉฐ, ์ ์ฒด ๋ฐ์ดํฐ๋ฅผ ์ฒ๋ฆฌํ๋ ๊ฒ์ด ์๋๋ผ ์ผ๋ถ ๋ฐ์ดํฐ๋ ๋จ์ผ ์์ ์ ์ฒ๋ฆฌํ๋ ๋ฐ ์ฃผ๋ก ์ฌ์ฉ๋ฉ๋๋ค.
Tasklet ๋ฐฉ์์ ์์ ํ๋ฆ์ ์๋์ ๊ฐ์ต๋๋ค.
- Tasklet ์ธํฐํ์ด์ค์ execute() ๋ฉ์๋๋ฅผ ๊ตฌํํ์ฌ ์ฌ์ฉํ๋ค. ์ด ๋ฉ์๋๋ ํ๋์ ํธ๋์ญ์ ๋ฒ์์์ ์คํ๋๋ค.
- execute() ๋ฉ์๋๋ RepeatStatus๋ฅผ ๋ฐํํ๋๋ฐ ์ด๋ Tasklet์ ์คํ ์ํ๋ฅผ ๋ํ๋ธ๋ค.
- RepeatStatus.FINISHED๋ฅผ ๋ฐํํ๋ฉด, ํด๋น Tasklet์ ์ฒ๋ฆฌ๊ฐ ์๋ฃ๋ ๊ฒ์ ์๋ฏธํ๋ค.
- RepeatStatus.CONTINUABLE๋ฅผ ๋ฐํํ๋ฉด, Tasklet์ด ๊ณ์ ์คํ๋์ด์ผ ํจ์ ์๋ฏธํ๋ค.
@Configuration
public class TaskletStepConfiguration {
@Autowired
private StepBuilderFactory stepBuilderFactory;
@Bean
public Step taskletStep() {
return stepBuilderFactory.get("taskletStep")
.tasklet((contribution, chunkContext) -> {
// ์ฌ๊ธฐ์ Tasklet ๋ก์ง ์์ฑ
System.out.println("Tasklet step executed");
return RepeatStatus.FINISHED;
})
.build();
}
}
Tasklet๋ฐฉ์์ ์์ ์ ๋จ์์ฑ๊ณผ ๋ช ํ์ฑ ๋๋ฌธ์ ํน์ ์ํฉ์์ ์ ์ฉํ๊ฒ ์ฌ์ฉ๋ ์ ์์ต๋๋ค. ๊ทธ๋ฌ๋ ๋ณต์กํ๊ฑฐ๋ ๋๋์ ๋ฐ์ดํฐ ์ฒ๋ฆฌ๋ฅผ ์๊ตฌํ๋ ๊ฒฝ์ฐ์๋ Chunk ๋ฐฉ์์ด ๋ ์ ํฉํฉ๋๋ค.
* Chunk ๋ฐฉ์
Chunk ๋ฐฉ์์ ๋์ฉ๋ ๋ฐ์ดํฐ๋ฅผ ํจ๊ณผ์ ์ผ๋ก ์ฒ๋ฆฌํ๊ธฐ ์ํด ์ฌ์ฉํฉ๋๋ค. ํฐ ๋ฐ์ดํฐ๋ฅผ ์ผ๋ จ์ ์์ ๋ฐ์ดํฐ ๋ฌถ์(Chunk)์ผ๋ก ๋๋๊ณ , ๊ฐ Chunk๋ฅผ ๊ฐ๋ณ์ ์ธ ํธ๋์ญ์ ๋ฒ์ ๋ด์์ ์ฒ๋ฆฌํ๋ ๋ฐฉ์์ ์ทจํฉ๋๋ค.
Chunk๋ฐฉ์์ ์์ ํ๋ฆ์ ์๋์ ๊ฐ์ต๋๋ค.
- ๊ฐ Chunk ์ฒ๋ฆฌ๋ Reader, Processor, Writer ์ธ ๋จ๊ณ๋ก ๊ตฌ์ฑ๋๋ค.
- Reader๋ ๋ฐ์ดํฐ ์์ค๋ก๋ถํฐ ๋ฐ์ดํฐ๋ฅผ ์ฝ์ด์์ Chunk๋ฅผ ์์ฑํ๋ค. ์ด ๋ฐ์ดํฐ๋ ์ผ๋ฐ์ ์ผ๋ก ๋ฐ์ดํฐ๋ฒ ์ด์ค๋, ํ์ผ, ๋๋ ๋ฉ์์ง ํ ๋ฑ์ด ๋ ์ ์๋ค.
- Processor๋ ์ฝ์ด์จ ๋ฐ์ดํฐ์ ๋ํด ํ์ํ ์ฒ๋ฆฌ๋ฅผ ์ํํ๋ค. ์ด ์ฒ๋ฆฌ๋ ๋ฐ์ดํฐ ๊ฒ์ฆ, ํํฐ๋ง, ๋ณํ ๋ฑ ๋ค์ํ ํํ๋ฅผ ๊ฐ์ง ์ ์๋ค.
- Writer๋ ์ฒ๋ฆฌ๋ ๋ฐ์ดํฐ๋ฅผ ์ต์ข ์ ์ผ๋ก ์ ์ฅํ๋ค.
๊ฐ๋จํ ์์ ์ฝ๋๋ ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
@Configuration
public class ChunkStepConfiguration {
@Autowired
private StepBuilderFactory stepBuilderFactory;
@Bean
public ItemReader<String> reader() {
return new ListItemReader<>(Arrays.asList("Ahn", "Ju", "Hyeong"));
}
@Bean
public ItemProcessor<String, String> processor() {
return item -> item.toUpperCase();
}
@Bean
public ItemWriter<String> writer() {
return items -> items.forEach(System.out::println);
}
@Bean
public Step chunkStep() {
return stepBuilderFactory.get("chunkStep")
.<String, String>chunk(10)
.reader(reader())
.processor(processor())
.writer(writer())
.build();
}
}
์ ์ฝ๋์์ ItemReader๋ "Ahn", "Ju", "Hyeong"์ด๋ผ๋ ๋ฌธ์์ด ๋ฆฌ์คํธ๋ฅผ ์ฝ์ด์์ ItemProcessor์์ ๊ฐ ๋ฌธ์์ด์ ๋๋ฌธ์๋ก ๋ณํํ์ฌ ItemWriter์์ ๊ฐ ํญ๋ชฉ์ ์ฝ์์ ์ถ๋ ฅํฉ๋๋ค.
์ข ๋ ์ธ๋ถ์ ์ธ JPA ํ๊ฒฝ์์ ์ฌ์ฉํ์ ๋์ ์์ ์ฝ๋๋ ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
@Configuration
@EnableBatchProcessing
public class BookOrderJobConfiguration {
@Autowired
private JobBuilderFactory jobBuilderFactory;
@Autowired
private StepBuilderFactory stepBuilderFactory;
@Autowired
private EntityManagerFactory entityManagerFactory;
// Job ์ค์
@Bean
@JobScope
public Job bookOrderJob() throws Exception {
return jobBuilderFactory.get("bookOrderJob")
.start(bookOrderStep()) // "bookOrderStep"์ด๋ผ๋ ์ด๋ฆ์ Step์ ์์์ ์ผ๋ก ์ค์
.build();
}
// Step ์ค์
@Bean
@StepScope
public Step bookOrderStep() throws Exception {
return stepBuilderFactory.get("bookOrderStep")
.<Book, Order>chunk(10) // ํ ๋ฒ์ ์ฒ๋ฆฌํ ๋ฐ์ดํฐ ํญ๋ชฉ์ ํฌ๊ธฐ(chunk size)๋ฅผ 10์ผ๋ก ์ค์
.reader(bookReader()) // Reader ์ค์
.processor(bookOrderProcessor()) // Processor ์ค์
.writer(orderWriter()) // Writer ์ค์
.build();
}
// Reader ์ค์ - ๋ฐ์ดํฐ๋ฒ ์ด์ค๋ก๋ถํฐ ํน์ ์กฐ๊ฑด์ ๋ง๋ ๋ฐ์ดํฐ๋ฅผ ์ฝ์ด์ค๋ ์ญํ
@Bean
@StepScope
public JpaPagingItemReader<Book> bookReader() throws Exception {
Map<String, Object> parameterValues = new HashMap<>();
parameterValues.put("stock", 5); // stock ํ๋ผ๋ฏธํฐ ๊ฐ์ 5๋ก ์ค์
return new JpaPagingItemReaderBuilder<Book>()
.name("JpaPagingItemReader")
.entityManagerFactory(entityManagerFactory)
.queryString("SELECT b FROM Book b WHERE b.stock <= :stock ORDER BY b.id ASC") // ์ฌ๊ณ ๊ฐ 5 ์ดํ์ธ ์ฑ
์ ์กฐํํ๋ ์ฟผ๋ฆฌ
.parameterValues(parameterValues)
.pageSize(10) // ํ์ด์ง ์ฌ์ด์ฆ๋ฅผ 10์ผ๋ก ์ค์
.build();
}
// Processor ์ค์ - ์ฝ์ด์จ ๋ฐ์ดํฐ๋ฅผ ๊ธฐ๋ฐ์ผ๋ก ๋น์ฆ๋์ค ๋ก์ง์ ์ํํ๋ ์ญํ
@Bean
@StepScope
public ItemProcessor<Book, Order> bookOrderProcessor() {
return book -> {
Order order = new Order();
order.setBook(book);
order.setQuantity(10); // Reorder quantity
return order; // ์ฌ๊ณ ๊ฐ ๋ถ์กฑํ ์ฑ
์ ๋ํด ์ฌ์ฃผ๋ฌธ์ ์์ฑ
};
}
// Writer ์ค์ - ์ฒ๋ฆฌ๋ ๊ฒฐ๊ณผ ๋ฐ์ดํฐ๋ฅผ ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ์ ์ฅํ๋ ์ญํ
@Bean
@StepScope
public JpaItemWriter<Order> orderWriter() {
return new JpaItemWriterBuilder<Order>()
.entityManagerFactory(entityManagerFactory)
.build();
}
}
์ ์ฝ๋๋ ์ฌ๊ณ ๊ฐ ํน์ ์๋ ์ดํ์ธ Book์ ๋ํด์ ์ฌ์ฃผ๋ฌธ(Order)์ ์์ฑํ๋ ์์ ์ ์ํํ๋ ์ฝ๋์ ๋๋ค. ์ฌ์ฃผ๋ฌธ ์์ ์ bookOrderJob์ด๋ผ๋ Job์ผ๋ก ๊ตฌ์ฑ๋๋ฉฐ, bookOrderStep์ด๋ผ๋ ๋จ์ผ Step์ ๊ฐ์ง๋๋ค.
Paging Size์ Chunk Size ๋?
Spring Batch๋ ๋์ฉ๋ ๋ฐ์ดํฐ๋ฅผ ํจ๊ณผ์ ์ผ๋ก ์ฒ๋ฆฌํ๊ธฐ ์ํด ItemReader์ ItemWriter๋ฅผ ์ ๊ณตํ๋๋ฐ ์ด ์ค Paging ์ฒ๋ฆฌ๋ ๋์ฉ๋ ๋ฐ์ดํฐ๋ฅผ ํจ์จ์ ์ผ๋ก ์ฝ์ด์ค๋ ๋ฐฉ๋ฒ ์ค ํ๋์ ๋๋ค.
- Paging์ ๋ฐ์ดํฐ๋ฅผ ์ผ์ ํ ํฌ๊ธฐ์ ํ์ด์ง๋ก ๋ถํ ํ์ฌ ์ฒ๋ฆฌํ๋ ๊ฒ์ ์๋ฏธํ๋๋ฐ, ์๋ฅผ ๋ค์ด ๋ง์ฝ ๋ฐ์ดํฐ๊ฐ 1000๊ฐ๊ฐ ์๊ณ ํ์ด์ง ํฌ๊ธฐ๋ฅผ 100์ผ๋ก ์ค์ ํ๋ค๋ฉด, ์ด 10ํ์ด์ง๋ก ๋ฐ์ดํฐ๋ฅผ ๋๋์ด ์ฒ๋ฆฌํ๊ฒ ๋ฉ๋๋ค.
- Chunk๋ Spring Batch์์ ํธ๋์ญ์ ๋ฒ์๋ฅผ ์ค์ ํ๋ ๋ฐฉ๋ฒ ์ค ํ๋์ ๋๋ค. Chunk size๋ ํ ๋ฒ์ ์ฒ๋ฆฌ(์ปค๋ฐ)๋ ๋ฐ์ดํฐ ํญ๋ชฉ์ ์๋ฅผ ์๋ฏธํ๋ฉฐ, ๋ง์ฝ Chunk size๋ฅผ 10์ผ๋ก ์ค์ ํ๋ค๋ฉด, ๊ฐ ํธ๋์ญ์ ์ 10๊ฐ์ ๋ฐ์ดํฐ ํญ๋ชฉ์ ์ฒ๋ฆฌํ๊ฒ ๋ฉ๋๋ค.
Paging Size์ Chunk Size์ ๊ด๊ณ
Paging Size๊ฐ 5์ด๊ณ , Chunk Size๊ฐ 10์ผ ๊ฒฝ์ฐ, 2๋ฒ์ Read๊ฐ ์ด๋ฃจ์ด์ง ํ์ 1๋ฒ์ Transaction์ด ์ํ๋ฉ๋๋ค. ์ด๋ ํ ๋ฒ์ Transaction์ ์ํด 2๋ฒ์ ์ฟผ๋ฆฌ ์ํ์ด ๋ฐ์ํ๊ฒ ๋๋ฏ๋ก, ์ด๋ฌํ ์ํฉ์ ํจ์จ์ ์ด์ง ์์ต๋๋ค.
๋ฐ๋ผ์ ํจ๊ณผ์ ์ธ ์ฑ๋ฅ ํฅ์์ ์ํด์ Spring Batch์์ ๊ถ์ฅํ๋ ๊ฒ์ฒ๋ผ ํ์ด์ง ํฌ๊ธฐ๋ฅผ ์๋นํ ํฌ๊ฒ ์ค์ ํ๊ณ ํ์ด์ง ํฌ๊ธฐ์ ์ผ์นํ๋ ์ปค๋ฐ ๊ฐ๊ฒฉ(Chunk Size)์ ์ฌ์ฉํ๋ ๊ฒ์ด ์ข์ต๋๋ค. ์ฆ Paging Size์ Chunk Size์ ๊ฐ์ ๊ฐ์ผ๋ก ์ค์ ํ๋ ๊ฒ์ ๋๋ค.
PagingReader ์ฌ์ฉ ์ ์ฃผ์์ฌํญ
ํ์ด์ง ์ฒ๋ฆฌ ์ ๊ฐ ์ฟผ๋ฆฌ์ Offset๊ณผ Limit๋ฅผ ์ง์ ํด ์ฃผ์ด์ผ ํ๋๋ฐ ์ด๋ PageSize๋ฅผ ์ง์ ํ๋ฉด Batch์์ Offset๊ณผ Limit๋ฅผ ์ง์ ํด ์ค๋๋ค. ํ์ง๋ง ํ์ด์ง ์ฒ๋ฆฌ๋ฅผ ํ ๋๋ง๋ค ์๋ก์ด ์ฟผ๋ฆฌ๋ฅผ ์คํํ๊ธฐ ๋๋ฌธ์ ๋ฐ์ดํฐ ์์๊ฐ ๋ณด์ฅ๋ ์ ์๋๋ก ๋ฐ๋์ Order By๋ฅผ ์ฌ์ฉํ์ฌ์ผ ํฉ๋๋ค.
Batch ํ ์คํธ ์ฝ๋
@RunWith(SpringRunner.class)
@SpringBootTest
public class SampleBatchJobTest {
// JobLauncherTestUtils๋ Spring Batch๊ฐ ์ ๊ณตํ๋ ์ ํธ๋ฆฌํฐ ํด๋์ค๋ก,
// Job์ ์คํํ๊ณ ๊ทธ ๊ฒฐ๊ณผ๋ฅผ ํ
์คํธํ๋๋ฐ ์ฌ์ฉ๋จ.
@Autowired
private JobLauncherTestUtils jobLauncherTestUtils;
// JobRepositoryTestUtils๋ Job ์คํ์ ๊ด๋ จ๋ ๋ฉํ๋ฐ์ดํฐ๋ฅผ ์ ๊ฑฐํ๋๋ฐ ์ฌ์ฉ,
// ์ด๋ฅผ ํตํด ๊ฐ ํ
์คํธ๊ฐ ๋
๋ฆฝ์ ์ผ๋ก ์คํ๋ ์ ์๋๋ก ๋ณด์ฅํจ.
@Autowired
private JobRepositoryTestUtils jobRepositoryTestUtils;
@Before
public void clearMetaData() {
jobRepositoryTestUtils.removeJobExecutions();
}
@Test
public void testJob() throws Exception {
// Job์ ์คํํ๊ณ ๊ทธ ๊ฒฐ๊ณผ๋ฅผ JobExecution ๊ฐ์ฒด๋ก ๋ฐ์.
JobExecution jobExecution = jobLauncherTestUtils.launchJob();
// ์คํ๋ Job์ ์ํ๊ฐ COMPLETED(์ฑ๊ณต์ ์ผ๋ก ์๋ฃ๋จ)์ธ์ง ํ์ธ
assertThat(jobExecution.getStatus()).isEqualTo(BatchStatus.COMPLETED);
}
}
๊ธฐ๋ณธ์ ์ผ๋ก ์์ ๊ฐ์ด ์์ฑํ ์ ์์ต๋๋ค.
์ฐธ๊ณ
'BackEnd๐ฑ > Spring' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
๋ถ์ฐ๋ฝ์ผ๋ก ์ ์ฐฉ์ ์ด๋ฒคํธ ๊ตฌํํ๊ธฐ (3) | 2023.08.31 |
---|---|
Spring Data Redis์ @Indexed ์ฌ์ฉ ์ ์ฃผ์์ (0) | 2023.08.07 |
WebClient์์ ์๋ฌ ์ฒ๋ฆฌ์ ์ฌ์๋ํ๋ ๋ฐฉ๋ฒ (0) | 2023.08.03 |
์คํ๋ง์์ @Async๋ฅผ ์ฌ์ฉํ ๋ ์ฃผ์์ (4) | 2023.07.24 |
Kafka ๊ฐ๋ ๊ณผ Spring Boot + Kafka ๊ฐ๋จํ ์ฐ๋ (1) | 2023.07.19 |
์คํ๋ง ์ด๋ฒคํธ ๋ฐํ๊ณผ ๊ตฌ๋ ์ผ๋ก ํธ๋์ญ์ ๋ถ๋ฆฌํ๊ธฐ (1) | 2023.07.09 |
๋๊ธ