{"id":19862407,"url":"https://github.com/cse0518/spring-batch_test","last_synced_at":"2025-07-17T07:04:28.882Z","repository":{"id":153551753,"uuid":"621210800","full_name":"cse0518/Spring-Batch_Test","owner":"cse0518","description":"기본적인 스프링 배치 프로그램을 실습합니다.","archived":false,"fork":false,"pushed_at":"2023-04-03T04:41:21.000Z","size":18,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-03-01T00:24:25.692Z","etag":null,"topics":["spring-batch"],"latest_commit_sha":null,"homepage":"","language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/cse0518.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2023-03-30T07:58:15.000Z","updated_at":"2023-04-23T11:26:17.000Z","dependencies_parsed_at":"2023-05-19T12:00:19.005Z","dependency_job_id":null,"html_url":"https://github.com/cse0518/Spring-Batch_Test","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/cse0518/Spring-Batch_Test","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cse0518%2FSpring-Batch_Test","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cse0518%2FSpring-Batch_Test/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cse0518%2FSpring-Batch_Test/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cse0518%2FSpring-Batch_Test/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/cse0518","download_url":"https://codeload.github.com/cse0518/Spring-Batch_Test/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cse0518%2FSpring-Batch_Test/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":265575472,"owners_count":23790776,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["spring-batch"],"created_at":"2024-11-12T15:11:42.782Z","updated_at":"2025-07-17T07:04:28.866Z","avatar_url":"https://github.com/cse0518.png","language":"Java","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Spring-Batch_Test\n\n- 스프링 배치 프로그램을 실습합니다.\n\n\u003cdetails\u003e\n\u003csummary\u003eJob Configuration\u003c/summary\u003e\n\u003cdiv\u003e\n\n- Spring Batch 5.0 이전 (기존 버전)\n  ```java\n  import lombok.RequiredArgsConstructor;\n  import org.springframework.batch.core.Job;\n  import org.springframework.batch.core.Step;\n  import org.springframework.batch.core.configuration.annotation.JobBuilderFactory;\n  import org.springframework.batch.core.configuration.annotation.StepBuilderFactory;\n  import org.springframework.batch.repeat.RepeatStatus;\n  import org.springframework.context.annotation.Bean;\n  import org.springframework.context.annotation.Configuration;\n  \n  @RequiredArgsConstructor\n  @Configuration\n  public class JobConfig {\n  \n      private final JobBuilderFactory jobBuilderFactory;\n      private final StepBuilderFactory stepBuilderFactory;\n  \n      @Bean\n      public Job simpleJob(Step step) {\n          return jobBuilderFactory.get(\"simpleJob\")\n                  .start(simpleStep1())\n                  .build();\n      }\n  \n      @Bean\n      public Step simpleStep1() {\n          return stepBuilderFactory.get(\"simpleStep1\")\n                  .tasklet((contribution, chunkContext) -\u003e RepeatStatus.FINISHED)\n                  .build();\n      }\n  }\n  ```\n\n- Spring Batch 5.0 이후\n  ```java\n  import lombok.RequiredArgsConstructor;\n  import org.springframework.batch.core.Job;\n  import org.springframework.batch.core.Step;\n  import org.springframework.batch.core.job.builder.JobBuilder;\n  import org.springframework.batch.core.repository.JobRepository;\n  import org.springframework.batch.core.step.builder.StepBuilder;\n  import org.springframework.batch.repeat.RepeatStatus;\n  import org.springframework.context.annotation.Bean;\n  import org.springframework.context.annotation.Configuration;\n  import org.springframework.transaction.PlatformTransactionManager;\n  \n  @RequiredArgsConstructor\n  @Configuration\n  public class JobConfig {\n  \n      private final JobRepository jobRepository;\n  \n      @Bean\n      public Job simpleJob(Step step) {\n          return new JobBuilder(\"simpleJob\", jobRepository)\n                  .start(step)\n                  .build();\n      }\n  \n      @Bean\n      public Step simpleStep(PlatformTransactionManager transactionManager) {\n          return new StepBuilder(\"simpleStep\", jobRepository)\n                  .tasklet((contribution, chunkContext) -\u003e RepeatStatus.FINISHED)\n                  .transactionManager(transactionManager)\n                  .build();\n      }\n  }\n  ```\n\n\u003c/div\u003e\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003eScope, Job Parameter\u003c/summary\u003e\n\u003cdiv\u003e\n\n- 파라미터를 받아 여러 Batch 컴포넌트에서 사용 → Job Parameter  \n  Job Parameter를 사용하기 위해선 항상 Scope를 선언해야함.\n  - `@JobScope`\n    - Step 선언문에서 사용 가능\n    - jobParameters와 jobExecutionContext 사용 가능\n    - ex) `@Value(\"#{jobParameters[파라미터명]}\")`\n  - `@StepScope`\n    - Tasklet 또는 ItemReader, ItemWriter, ItemProcessor에서 사용 가능\n    - jobParameters와 stepExecutionContext 사용 가능\n- default proxyMode\n  ```java\n  @Scope(value = \"step\", proxyMode = ScopedProxyMode.TARGET_CLASS)\n  @Retention(RetentionPolicy.RUNTIME)\n  @Documented\n  public @interface StepScope {\n  \n  }\n  ```\n  - 메소드의 리턴 타입을 구현체의 타입으로 사용해야 함.\n    - ItemReader 부분이 Proxy 객체로 생성되어 문제 발생.\n      ```java\n      @Bean\n      @StepScope\n      public ItemReader\u003cMember\u003e reader(@Value(\"#{jobParameters[firstName]}\") String firstName) {\n          Map\u003cString, Object\u003e paramMap = new HashMap\u003c\u003e();\n          paramMap.put(\"firstName\", firstName);\n    \n          JpaPagingItemReader\u003cMember\u003e reader = new JpaPagingItemReader\u003c\u003e();\n          reader.setQueryString(\"Select m From Member m where m.firstName=:firstName\");\n          reader.setParameterValues(paramMap);\n          reader.setEntityManagerFactory(entityManagerFactory);\n          reader.setPageSize(10);\n    \n          return reader;\n      }\n      ```\n    - 메소드의 리턴 타입을 구현체의 타입으로 지정해서 해결.\n      ```java\n      @Bean\n      @StepScope\n      public JpaPagingItemReader\u003cMember\u003e reader(@Value(\"#{jobParameters[firstName]}\") String firstName) {\n          Map\u003cString, Object\u003e paramMap = new HashMap\u003c\u003e();\n          paramMap.put(\"firstName\", firstName);\n    \n          JpaPagingItemReader\u003cMember\u003e reader = new JpaPagingItemReader\u003c\u003e();\n          reader.setQueryString(\"Select m From Member m where m.firstName=:firstName\");\n          reader.setParameterValues(paramMap);\n          reader.setEntityManagerFactory(entityManagerFactory);\n          reader.setPageSize(10);\n    \n          return reader;\n      }\n      ```\n\n\u003c/div\u003e\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003eChunk\u003c/summary\u003e\n\u003cdiv\u003e\n\n- `Chunk`\n  - 데이터 덩어리로 작업할 때 각 커밋 사이에 처리되는 row 수\n  - 한 번에 하나의 Item 단위로 데이터를 읽어서(read) 가공하고(process), Chunk 단위로 트랜잭션을 처리한다(write).\n  - 실패할 경우 chunk 단위로 롤백됨. 이전 chunk 범위는 반영.\n- `Page size` vs `Chunk size`\n  - `Page size`는 한 번에 조회할 Item 수\n  - `Chunk size`는 한 번에 처리될 트랜잭션 단위\n  - 즉, Page 단위로 끊어서 조회하고 Chunk 단위로 끊어서 처리한다.  \n    Page size와 Chunk size가 다를 경우 여러번의 비효율적인 쿼리가 발생하기 때문에 **같게 설정하는 것이 좋다.**\n\n\u003c/div\u003e\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e운영 환경에서 실행 명령\u003c/summary\u003e\n\u003cdiv\u003e\n\n```shell\njava -jar batch-application.jar --job.name=simpleJob\n```\n\n\u003c/div\u003e\n\u003c/details\u003e\n\n## References\n\n- [Jojoldu(이동욱) 님의 블로그 - Spring Batch 가이드](https://jojoldu.tistory.com/category/Spring%20Batch)\n- [Spring Batch 5.0 Migration 가이드 (공식 문서)](https://github.com/spring-projects/spring-batch/wiki/Spring-Batch-5.0-Migration-Guide)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcse0518%2Fspring-batch_test","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcse0518%2Fspring-batch_test","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcse0518%2Fspring-batch_test/lists"}