{"id":1823,"date":"2025-11-08T12:37:32","date_gmt":"2025-11-08T03:37:32","guid":{"rendered":"https:\/\/route-zero.com\/recruit\/?post_type=route&#038;p=1823"},"modified":"2026-01-08T12:37:42","modified_gmt":"2026-01-08T03:37:42","slug":"spring-boot-batch%e7%8f%be%e5%a0%b4%e5%b0%8e%e5%85%a5%e3%82%ac%e3%82%a4%e3%83%89%ef%bd%9c%e3%83%90%e3%83%83%e3%83%81%e5%87%a6%e7%90%86%e3%81%ae%e8%a8%ad%e8%a8%88%e3%83%bb%e5%ae%9f%e8%a3%85%e3%83%bb","status":"publish","type":"route","link":"https:\/\/route-zero.com\/recruit\/route\/1823\/","title":{"rendered":"Spring Boot Batch\u73fe\u5834\u5c0e\u5165\u30ac\u30a4\u30c9\uff5c\u30d0\u30c3\u30c1\u51e6\u7406\u306e\u8a2d\u8a08\u30fb\u5b9f\u88c5\u30fb\u30a8\u30e9\u30fc\u5bfe\u7b56\u304c\u3053\u308c\u4e00\u3064\u3067\u308f\u304b\u308b\uff01"},"content":{"rendered":"<div>\n<h2>\u306f\u3058\u3081\u306b<\/h2>\n<p>\u300c\u591c\u9593\u306e\u30c7\u30fc\u30bf\u96c6\u8a08\u3001Spring Boot Batch\u3067\u5b9f\u88c5\u3057\u3066\u307f\u3066\u300d\u2015\u2015\u7a81\u7136\u305d\u3093\u306a\u30bf\u30b9\u30af\u304c\u964d\u3063\u3066\u304d\u3066\u3001 \u3069\u3053\u304b\u3089\u624b\u3092\u3064\u3051\u308c\u3070\u3044\u3044\u306e\u304b\u60a9\u3093\u3060\u7d4c\u9a13\u306f\u3042\u308a\u307e\u305b\u3093\u304b\uff1f<\/p>\n<p><strong>Job<\/strong>\u3001<strong>Step<\/strong>\u3001<strong>Chunk<\/strong>\u2026\u2026\u65ad\u7247\u7684\u306a\u60c5\u5831\u3060\u3051\u3067\u306f\u5168\u4f53\u50cf\u304c\u898b\u3048\u305a\u3001\u672c\u5f53\u306b\u672c\u756a\u904b\u7528\u3067\u304d\u308b\u306e\u304b\u4e0d\u5b89\u306b\u306a\u308a\u304c\u3061\u3002<\/p>\n<p>\n    \u79c1\u305f\u3061\u3082\u300c\u8179\u843d\u3061\u300d\u3057\u306b\u304f\u3044\u3068\u611f\u3058\u3066\u304d\u307e\u3057\u305f\u3002 \u305d\u3053\u3067\u3053\u306e\u8a18\u4e8b\u3067\u306f\u3001<strong>\u73fe\u5834\u76ee\u7dda\u3067Spring Boot Batch\u306e\u5b9f\u8df5\u30ce\u30a6\u30cf\u30a6<\/strong>\u3092\u307e\u3068\u3081\u307e\u3059\u3002<br \/>\n    \u56f3\u89e3\u3067\u7406\u89e3\u2192\u5373\u30b3\u30d4\u30da\u3067\u52d5\u4f5c\u2192\u672c\u756a\u5fc5\u9808\u306e\u904b\u7528\u30c6\u30af\u307e\u3067\u3001\u4e00\u6c17\u306b\u201c\u8179\u843d\u3061\u201d\u3092\u72d9\u3044\u307e\u3059\u3002\n  <\/p>\n<hr \/>\n<h2>1. \u307e\u305a\u62bc\u3055\u3048\u305f\u3044\uff01Spring Boot Batch\u306e3\u3064\u306e\u30b3\u30a2\u6982\u5ff5\u3010\u56f3\u89e3\u3042\u308a\u3011<\/h2>\n<p>\u300c<strong>Spring Boot Batch<\/strong>\u3063\u3066\u4f55\uff1f\u300d\u3068\u3044\u3046\u7591\u554f\u3001 \u3088\u304f\u3042\u308b\u65ad\u7247\u60c5\u5831\u3067\u306f\u3001\u5b9f\u52d9\u3067\u306f\u304b\u3048\u3063\u3066\u6df7\u4e71\u3057\u307e\u305b\u3093\u304b\uff1f<\/p>\n<p>\u79c1\u305f\u3061\u304c\u8179\u843d\u3061\u3059\u308b\u306b\u306f\u3001 \u300c<strong>Job<\/strong>\u300d\u300c<strong>Step<\/strong>\u300d\u300c<strong>JobRepository<\/strong>\u300d\u306e3\u672c\u67f1\u3092 <strong>\u6599\u7406\u306e\u624b\u9806<\/strong>\u306b\u305f\u3068\u3048\u3066\u30a4\u30e1\u30fc\u30b8\u3059\u308b\u3068\u30b9\u30c3\u3068\u7406\u89e3\u3067\u304d\u307e\u3059\u3002<\/p>\n<ul>\n<li><strong>Job<\/strong>\uff1a\u30d0\u30c3\u30c1\u5168\u4f53\u306e\u201c\u30ab\u30ec\u30fc\u3092\u4f5c\u308b\u201d\u30bf\u30b9\u30af\u672c\u4f53<\/li>\n<li><strong>Step<\/strong>\uff1a\u305d\u306e\u4e2d\u306e\u201c\u91ce\u83dc\u3092\u5207\u308b\u201d\u201c\u8089\u3092\u7092\u3081\u308b\u201d\u306a\u3069\u5404\u5de5\u7a0b<\/li>\n<li><strong>JobRepository<\/strong>\uff1a\u9032\u6357\u30fb\u5c65\u6b74\u3092\u8a18\u9332\u3059\u308b\u201c\u30ec\u30b7\u30d4\u53f0\u5e33\u201d<\/li>\n<\/ul>\n<blockquote>\n<p><strong>\u7528\u8a9e\u89e3\u8aac\uff1aSpring Boot Batch<\/strong> Java\u3067\u30d0\u30c3\u30c1\u51e6\u7406\uff08\u5b9a\u671f\u7684\u306a\u30c7\u30fc\u30bf\u96c6\u8a08\u3084\u4e00\u62ec\u66f4\u65b0\u306a\u3069\uff09\u3092\u52b9\u7387\u3088\u304f\u5b9f\u88c5\u3067\u304d\u308b\u30d5\u30ec\u30fc\u30e0\u30ef\u30fc\u30af\u3002\u696d\u52d9\u30b7\u30b9\u30c6\u30e0\u3067\u3088\u304f\u4f7f\u308f\u308c\u308b\u3002<\/p>\n<p><strong>\u7528\u8a9e\u89e3\u8aac\uff1aJob<\/strong> \u30d0\u30c3\u30c1\u51e6\u7406\u5168\u4f53\u306e\u300c\u89aa\u300d\u5358\u4f4d\u3002\u4f8b\u3048\u3070\u300c\u58f2\u4e0a\u96c6\u8a08\u30d0\u30c3\u30c1\u300d\u306a\u3069\u3001\u307e\u3068\u307e\u3063\u305f\u696d\u52d9\u51e6\u7406\u306e\u672c\u4f53\u3002<\/p>\n<p><strong>\u7528\u8a9e\u89e3\u8aac\uff1aStep<\/strong> Job\u306e\u4e2d\u306e\u500b\u5225\u5de5\u7a0b\u3002\u30c7\u30fc\u30bf\u8aad\u8fbc\u30fb\u52a0\u5de5\u30fb\u66f8\u51fa\u3057\u306a\u3069\u3001\u51e6\u7406\u306e\u624b\u9806\u3054\u3068\u306b\u5206\u5272\u3067\u304d\u308b\u3002<\/p>\n<p><strong>\u7528\u8a9e\u89e3\u8aac\uff1aChunk<\/strong> \u5927\u91cf\u30c7\u30fc\u30bf\u3092\u4e00\u5b9a\u4ef6\u6570\u305a\u3064\u5206\u5272\u3057\u3066\u51e6\u7406\u3059\u308b\u4ed5\u7d44\u307f\u3002\u30e1\u30e2\u30ea\u52b9\u7387\u3084\u30a8\u30e9\u30fc\u8010\u6027\u306b\u512a\u308c\u308b\u3002<\/p>\n<p><strong>\u7528\u8a9e\u89e3\u8aac\uff1aJobRepository<\/strong> \u30d0\u30c3\u30c1\u306e\u5b9f\u884c\u5c65\u6b74\u3084\u9032\u6357\u3092\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\u306b\u8a18\u9332\u3059\u308b\u4ed5\u7d44\u307f\u3002\u9014\u4e2d\u5931\u6557\u6642\u306e\u518d\u958b\u3084\u904b\u7528\u7ba1\u7406\u306b\u5fc5\u9808\u3002<\/p>\n<\/blockquote>\n<p>\n    \uff08Spring Boot\u306e\u4f9d\u5b58\u7ba1\u7406\u3084pom.xml\u306b\u3064\u3044\u3066\u306f\u300e<a href=\"https:\/\/route-zero.com\/recruit\/route\/1732\/\" target=\"_blank\" rel=\"noopener\">Spring Boot pom.xml\u5fb9\u5e95\u89e3\u8aac\uff5c2025\u5e74\u7248 \u4f9d\u5b58\u7ba1\u7406\u30fb\u30d0\u30fc\u30b8\u30e7\u30f3\u7af6\u5408\u306e\u5168\u5bfe\u7b56<\/a\n    >\u300f\u3092\u3054\u53c2\u7167\u304f\u3060\u3055\u3044\uff09\n  <\/p>\n<h3><strong>Job<\/strong> \u2015 \u30d0\u30c3\u30c1\u5168\u4f53\u306e\u201c\u89aa\u201d<\/h3>\n<p>\n    \u30d0\u30c3\u30c1\u51e6\u7406\u306e\u6700\u4e0a\u4f4d\u5358\u4f4d\u304c<strong>Job<\/strong>\u3002 \u300c\u65e5\u6b21\u58f2\u4e0a\u96c6\u8a08\u30d0\u30c3\u30c1\u300d\u306a\u3069\u3001\u3072\u3068\u307e\u3068\u307e\u308a\u306e\u696d\u52d9\u51e6\u7406\u3092\u307e\u308b\u3054\u3068\u30ab\u30d7\u30bb\u30eb\u5316\u3057\u307e\u3059\u3002<br \/>\n    Job\u306f\u5fc5\u305a1\u3064\u4ee5\u4e0a\u306e<strong>Step<\/strong>\u3067\u69cb\u6210\u3055\u308c\u3001\u3069\u306eStep\u3092\u3069\u306e\u9806\u756a\u3067\u5b9f\u884c\u3059\u308b\u304b\u5b9a\u7fa9\u3067\u304d\u307e\u3059\u3002\n  <\/p>\n<h3><strong>Step<\/strong> \u2015 \u500b\u5225\u306e\u201c\u624b\u9806\u201d\u62c5\u5f53\uff08Tasklet\uff0fChunk\uff09<\/h3>\n<p><strong>Step<\/strong>\u306f\u30d0\u30c3\u30c1\u51e6\u7406\u306e\u69cb\u6210\u8981\u7d20\u3002 \u5b9f\u306f2\u7a2e\u985e\u306e\u30e2\u30c7\u30eb\u304c\u3042\u308a\u307e\u3059\u3002<\/p>\n<ul>\n<li><strong>Tasklet\u30e2\u30c7\u30eb<\/strong>\uff1a\u4e00\u5ea6\u3060\u3051\u5b9f\u884c\u3059\u308b\u5358\u7d14\u4f5c\u696d\uff08\u4f8b\uff1a\u4e8b\u524d\u30d5\u30a1\u30a4\u30eb\u524a\u9664\uff09<\/li>\n<li><strong>Chunk\u30e2\u30c7\u30eb<\/strong>\uff1a\u5927\u91cf\u30c7\u30fc\u30bf\u3092\u201c\u5c11\u3057\u305a\u3064\u5206\u5272\u201d\u3057\u3066\u8aad\u8fbc\u307f\u2192\u52a0\u5de5\u2192\u66f8\u51fa\u3057\uff08\u4e3b\u5f79\u306f\u3053\u3061\u3089\uff09<\/li>\n<\/ul>\n<p>\n    \uff08Spring Boot\u306e\u30d1\u30e9\u30e1\u30fc\u30bf\u53d7\u3051\u53d6\u308a\u3084DI\/IoC\u306b\u3064\u3044\u3066\u306f\u300e<a href=\"https:\/\/route-zero.com\/recruit\/route\/1336\/\" target=\"_blank\" rel=\"noopener\">Spring Boot \u306e\u30d1\u30e9\u30e1\u30fc\u30bf\u53d7\u3051\u53d6\u308a\uff5c@ModelAttribute \u3068 @RequestBody \u306e\u9055\u3044\u3068\u4f7f\u3044\u5206\u3051<\/a\n    >\u300f\u3082\u3054\u53c2\u7167\u304f\u3060\u3055\u3044\uff09\n  <\/p>\n<blockquote>\n<p><strong>\u7528\u8a9e\u89e3\u8aac\uff1aTasklet<\/strong> 1\u56de\u3060\u3051\u5b9f\u884c\u3059\u308b\u5358\u7d14\u306a\u51e6\u7406\uff08\u4f8b\uff1a\u30d5\u30a1\u30a4\u30eb\u524a\u9664\u3084\u521d\u671f\u5316\u306a\u3069\uff09\u3092\u62c5\u5f53\u3059\u308bStep\u306e\u5b9f\u88c5\u65b9\u5f0f\u3002<\/p>\n<p><strong>\u7528\u8a9e\u89e3\u8aac\uff1aChunk\u30e2\u30c7\u30eb<\/strong> \u30c7\u30fc\u30bf\u3092\u5206\u5272\uff08\u30c1\u30e3\u30f3\u30af\uff09\u3057\u3066\u3001\u8aad\u8fbc\u2192\u52a0\u5de5\u2192\u66f8\u51fa\u3057\u3092\u7e70\u308a\u8fd4\u3059\u65b9\u5f0f\u3002\u5927\u91cf\u30c7\u30fc\u30bf\u51e6\u7406\u306e\u4e3b\u5f79\u3002<\/p>\n<\/blockquote>\n<h3><strong>JobRepository<\/strong> \u2015 \u5b9f\u884c\u8a18\u9332\u306e\u201c\u9ed2\u5b50\u201d<\/h3>\n<p>\u30d0\u30c3\u30c1\u306e\u5b9f\u884c\u72b6\u614b\uff08\u958b\u59cb\u30fb\u6210\u529f\u30fb\u5931\u6557\u306a\u3069\uff09\u3092DB\u306b\u6c38\u7d9a\u5316\u3057\u3001 \u9014\u4e2d\u5931\u6557\u6642\u306b\u3082\u300c\u3069\u3053\u304b\u3089\u518d\u958b\uff1f\u300d\u3092\u5224\u65ad\u3067\u304d\u307e\u3059\u3002 \u3053\u308c\u304cSpring Batch\u306e\u201c\u5805\u7262\u3055\u201d\u306e\u6839\u5e79\u3067\u3059\u3002<\/p>\n<hr \/>\n<h2>2. \u3010\u624b\u3092\u52d5\u304b\u3059\u3011\u6700\u5c0f\u69cb\u6210\uff01Tasklet\u30e2\u30c7\u30eb\u3067Hello World\u30d0\u30c3\u30c1<\/h2>\n<p>\u300c\u3068\u308a\u3042\u3048\u305a\u30d0\u30c3\u30c1\u3092\u201c\u52d5\u304b\u3059\u201d\u306b\u306f\uff1f\u300d \u6700\u5c0f\u69cb\u6210\u306e<strong>Tasklet<\/strong>\u30e2\u30c7\u30eb\u3067\u201cHello, World!\u201d\u3092\u51fa\u529b\u3057\u3066\u307f\u307e\u3059\u3002<\/p>\n<p>\n    \uff08Spring Boot\u306e\u8a2d\u5b9a\u30d5\u30a1\u30a4\u30eb\u3084\u30a8\u30e9\u30fc\u5bfe\u7b56\u306b\u3064\u3044\u3066\u306f\u300e<a href=\"https:\/\/route-zero.com\/recruit\/route\/1624\/\" target=\"_blank\" rel=\"noopener\">Spring Boot NullPointerException\u5b8c\u5168\u5bfe\u7b56\uff5c3\u5927\u539f\u56e0\u3068\u5b9f\u88c5\u4f8b\u307e\u3068\u3081<\/a\n    >\u300f\u3082\u3054\u53c2\u7167\u304f\u3060\u3055\u3044\uff09\n  <\/p>\n<blockquote>\n<p><strong>\u7528\u8a9e\u89e3\u8aac\uff1abuild.gradle<\/strong> Java\u30d7\u30ed\u30b8\u30a7\u30af\u30c8\u306e\u4f9d\u5b58\u30e9\u30a4\u30d6\u30e9\u30ea\u3084\u8a2d\u5b9a\u3092\u7ba1\u7406\u3059\u308b\u30d5\u30a1\u30a4\u30eb\u3002Spring Boot Batch\u5229\u7528\u6642\u306f\u5fc5\u9808\u3002<\/p>\n<p><strong>\u7528\u8a9e\u89e3\u8aac\uff1aBean\u5b9a\u7fa9<\/strong> Spring\u3067\u7ba1\u7406\u3059\u308b\u90e8\u54c1\uff08Job\u3084Step\u306a\u3069\uff09\u3092\u30d7\u30ed\u30b0\u30e9\u30e0\u4e0a\u3067\u767b\u9332\u3059\u308b\u4ed5\u7d44\u307f\u3002<\/p>\n<p><strong>\u7528\u8a9e\u89e3\u8aac\uff1aapplication.properties<\/strong> Spring Boot\u306e\u8a2d\u5b9a\u30d5\u30a1\u30a4\u30eb\u3002\u30d0\u30c3\u30c1\u306e\u81ea\u52d5\u8d77\u52d5\u3084DB\u63a5\u7d9a\u60c5\u5831\u306a\u3069\u3092\u8a18\u8ff0\u3059\u308b\u3002<\/p>\n<\/blockquote>\n<h3>build.gradle\u306e\u8a2d\u5b9a<\/h3>\n<pre><code>dependencies {\r\n    implementation(\"org.springframework.boot:spring-boot-starter-batch\")\r\n    runtimeOnly(\"com.h2database:h2\")\r\n}<\/code><\/pre>\n<h3>Job\/Step\u306eBean\u5b9a\u7fa9\u3068\u5b9f\u884c\u4f8b<\/h3>\n<pre><code>import org.springframework.batch.core.Job;\r\nimport org.springframework.batch.core.Step;\r\nimport org.springframework.batch.core.job.builder.JobBuilder;\r\nimport org.springframework.batch.core.repository.JobRepository;\r\nimport org.springframework.batch.core.step.builder.StepBuilder;\r\nimport org.springframework.batch.core.step.tasklet.Tasklet;\r\nimport org.springframework.batch.repeat.RepeatStatus;\r\nimport org.springframework.context.annotation.Bean;\r\nimport org.springframework.context.annotation.Configuration;\r\nimport org.springframework.transaction.PlatformTransactionManager;\r\n\r\n@Configuration\r\npublic class HelloWorldJobConfig {\r\n    @Bean\r\n    public Step helloWorldStep(JobRepository jobRepository, PlatformTransactionManager transactionManager) {\r\n        return new StepBuilder(\"helloWorldStep\", jobRepository)\r\n                .tasklet((contribution, chunkContext) -> {\r\n                    System.out.println(\"Hello, Spring Boot Batch!\");\r\n                    return RepeatStatus.FINISHED;\r\n                }, transactionManager)\r\n                .build();\r\n    }\r\n\r\n    @Bean\r\n    public Job helloWorldJob(JobRepository jobRepository, Step helloWorldStep) {\r\n        return new JobBuilder(\"helloWorldJob\", jobRepository)\r\n                .start(helloWorldStep)\r\n                .build();\r\n    }\r\n}\r\n<\/code><\/pre>\n<p><strong>application.properties<\/strong>\u3067 <strong>spring.batch.job.enabled=false<\/strong>\u3092\u8a2d\u5b9a\u3057\u3001\u8d77\u52d5\u3059\u308b\u3068\u3001 \u300cHello, Spring Boot Batch!\u300d\u304c\u30b3\u30f3\u30bd\u30fc\u30eb\u306b\u51fa\u529b\u3055\u308c\u307e\u3059\u3002<\/p>\n<hr \/>\n<h2>3. \u672c\u547d\u306f\u3053\u308c\uff01Chunk\u30e2\u30c7\u30eb\u3067DB\u2192CSV\u30a8\u30af\u30b9\u30dd\u30fc\u30c8<\/h2>\n<p>\n    \u300c\u306a\u305c<strong>Chunk<\/strong>\u30e2\u30c7\u30eb\u304c\u63a8\u3055\u308c\u308b\u306e\u304b\uff1f\u300d 100\u4e07\u4ef6\u306e\u30c7\u30fc\u30bf\u3092\u4e00\u6c17\u306b\u30e1\u30e2\u30ea\u306b\u8f09\u305b\u308b\u3068\u3001OutOfMemory\u306e\u5371\u967a\u5927\u3002 <strong>Chunk<\/strong>\u30e2\u30c7\u30eb\u306f\u300c1000\u4ef6\u305a\u3064\u51e6\u7406\u2192\u66f8\u304d\u51fa\u3057\u300d\u3092\u7e70\u308a\u8fd4\u3057\u3001<br \/>\n    \u30e1\u30e2\u30ea\u4f7f\u7528\u91cf\u3092\u4e00\u5b9a\u306b\u6291\u3048\u307e\u3059\u3002\n  <\/p>\n<p>\n    \uff08JPA\u3084nativeQuery\u306e\u4f7f\u3044\u5206\u3051\u306b\u3064\u3044\u3066\u306f\u300e<a href=\"https:\/\/route-zero.com\/recruit\/route\/1670\/\" target=\"_blank\" rel=\"noopener\">Spring Boot Repository\u5fb9\u5e95\u89e3\u8aac\uff5cJPA\u30fbnativeQuery\u306e\u4f7f\u3044\u65b9\u3068\u5931\u6557\u4f8b<\/a\n    >\u300f\u3082\u3054\u53c2\u7167\u304f\u3060\u3055\u3044\uff09\n  <\/p>\n<blockquote>\n<p><strong>\u7528\u8a9e\u89e3\u8aac\uff1aItemReader<\/strong> \u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\u3084\u30d5\u30a1\u30a4\u30eb\u306a\u3069\u304b\u3089\u30c7\u30fc\u30bf\u3092\u8aad\u307f\u8fbc\u3080\u90e8\u54c1\u3002Chunk\u30e2\u30c7\u30eb\u306e\u6700\u521d\u306e\u5de5\u7a0b\u3002<\/p>\n<p><strong>\u7528\u8a9e\u89e3\u8aac\uff1aItemProcessor<\/strong> \u8aad\u307f\u8fbc\u3093\u3060\u30c7\u30fc\u30bf\u3092\u52a0\u5de5\u30fb\u5909\u63db\u30fb\u30d5\u30a3\u30eb\u30bf\u3059\u308b\u90e8\u54c1\u3002\u4e0d\u8981\u30c7\u30fc\u30bf\u306e\u9664\u5916\u306a\u3069\u3082\u62c5\u5f53\u3002<\/p>\n<p><strong>\u7528\u8a9e\u89e3\u8aac\uff1aItemWriter<\/strong> \u52a0\u5de5\u6e08\u307f\u30c7\u30fc\u30bf\u3092\u30d5\u30a1\u30a4\u30eb\u3084DB\u306b\u66f8\u304d\u51fa\u3059\u90e8\u54c1\u3002CSV\u51fa\u529b\u306a\u3069\u3067\u5229\u7528\u3002<\/p>\n<\/blockquote>\n<h3><strong>ItemReader<\/strong>\uff1aJPA + Paging\u3067\u52b9\u7387\u8aad\u8fbc<\/h3>\n<pre><code>@Bean\r\npublic JpaPagingItemReader&lt;User&gt; userItemReader(EntityManagerFactory emf) {\r\n    return new JpaPagingItemReaderBuilder&lt;User&gt;()\r\n        .name(\"userItemReader\")\r\n        .entityManagerFactory(emf)\r\n        .queryString(\"SELECT u FROM User u ORDER BY u.id\")\r\n        .pageSize(1000)\r\n        .build();\r\n}\r\n<\/code><\/pre>\n<h3><strong>ItemProcessor<\/strong>\uff1a\u30c7\u30fc\u30bf\u5909\u63db\u30fb\u30d5\u30a3\u30eb\u30bf\u3082\u3053\u3053<\/h3>\n<pre><code>public class UserProcessor implements ItemProcessor&lt;User, UserCsvDto&gt; {\r\n    @Override\r\n    public UserCsvDto process(User user) {\r\n        if (!user.isActive()) {\r\n            return null; \/\/ \u7121\u52b9\u30e6\u30fc\u30b6\u30fc\u306f\u30b9\u30ad\u30c3\u30d7\r\n        }\r\n        UserCsvDto dto = new UserCsvDto();\r\n        dto.setName(user.getFirstName() + \" \" + user.getLastName());\r\n        dto.setEmail(user.getEmail());\r\n        return dto;\r\n    }\r\n}\r\n<\/code><\/pre>\n<h3><strong>ItemWriter<\/strong>\uff1aCSV\u51fa\u529b\u3082\u30b7\u30f3\u30d7\u30eb\u306b<\/h3>\n<pre><code>@Bean\r\npublic FlatFileItemWriter&lt;UserCsvDto&gt; userItemWriter() {\r\n    return new FlatFileItemWriterBuilder&lt;UserCsvDto&gt;()\r\n        .name(\"userItemWriter\")\r\n        .resource(new FileSystemResource(\"output\/users.csv\"))\r\n        .delimited()\r\n        .names(\"name\", \"email\")\r\n        .headerCallback(writer -&gt; writer.write(\"Name,Email\"))\r\n        .build();\r\n}\r\n<\/code><\/pre>\n<hr \/>\n<h2>4. \u672c\u756a\u54c1\u8cea\uff01\u30a8\u30e9\u30fc\u51e6\u7406\u3068\u30d0\u30c3\u30c1\u30c6\u30b9\u30c8<\/h2>\n<p>\u300c\u30d0\u30c3\u30c1\u306f\u201c\u52d5\u304f\u3060\u3051\u201d\u3058\u3083\u30c0\u30e1\u3002\u6b62\u307e\u3089\u305a\u56de\u5fa9\u3067\u304d\u308b\u8a2d\u8a08\u304c\u8981\uff01\u300d \u73fe\u5834\u3067\u52b9\u304f\u3001\u4ee3\u8868\u7684\u306a\u30a8\u30e9\u30fc\u8010\u6027\u624b\u6cd5\u3092\u7d39\u4ecb\u3057\u307e\u3059\u3002<\/p>\n<p>\n    \uff08Spring Boot\u30c6\u30b9\u30c8\u8a2d\u8a08\u3084TDD\u306b\u3064\u3044\u3066\u306f\u300e<a href=\"https:\/\/route-zero.com\/recruit\/route\/1386\/\" target=\"_blank\" rel=\"noopener\">Spring Boot\u30c6\u30b9\u30c8\u8a2d\u8a08\u5165\u9580\uff1aTDD\u00d7\u30e2\u30c3\u30af\u00d7CI\u81ea\u52d5\u5316\u30ac\u30a4\u30c9<\/a\n    >\u300f\u3082\u3054\u53c2\u7167\u304f\u3060\u3055\u3044\uff09\n  <\/p>\n<blockquote>\n<p><strong>\u7528\u8a9e\u89e3\u8aac\uff1aSkip<\/strong> \u7279\u5b9a\u306e\u4f8b\u5916\u767a\u751f\u6642\u306b\u3001\u305d\u306e\u30c7\u30fc\u30bf\u3060\u3051\u30b9\u30ad\u30c3\u30d7\u3057\u3066\u51e6\u7406\u3092\u7d99\u7d9a\u3059\u308b\u4ed5\u7d44\u307f\u3002\u30a8\u30e9\u30fc\u8010\u6027\u5411\u4e0a\u306b\u6709\u52b9\u3002<\/p>\n<p><strong>\u7528\u8a9e\u89e3\u8aac\uff1aRetry<\/strong> \u4e00\u6642\u7684\u306a\u30a8\u30e9\u30fc\uff08DB\u30ed\u30c3\u30af\u306a\u3069\uff09\u304c\u767a\u751f\u3057\u305f\u5834\u5408\u3001\u6307\u5b9a\u56de\u6570\u307e\u3067\u518d\u8a66\u884c\u3059\u308b\u4ed5\u7d44\u307f\u3002<\/p>\n<p><strong>\u7528\u8a9e\u89e3\u8aac\uff1aJobLauncherTestUtils<\/strong> Spring Batch\u306eJob\u3092\u30c6\u30b9\u30c8\u81ea\u52d5\u5316\u3059\u308b\u305f\u3081\u306e\u30e6\u30fc\u30c6\u30a3\u30ea\u30c6\u30a3\u3002\u30d0\u30c3\u30c1\u306e\u54c1\u8cea\u62c5\u4fdd\u306b\u5f79\u7acb\u3064\u3002<\/p>\n<\/blockquote>\n<h3>&#x2705; \u65b9\u6cd51\uff1a\u7279\u5b9a\u4f8b\u5916\u3092\u30b9\u30ad\u30c3\u30d7\uff08<strong>Skip<\/strong>\uff09<\/h3>\n<pre><code>@Bean\r\npublic Step chunkStep(..., ItemReader&lt;User&gt; reader, ItemProcessor&lt;User, UserCsvDto&gt; processor, ItemWriter&lt;UserCsvDto&gt; writer) {\r\n    return new StepBuilder(\"chunkStep\", jobRepository)\r\n        .&lt;User, UserCsvDto&gt;chunk(1000, transactionManager)\r\n        .reader(reader)\r\n        .processor(processor)\r\n        .writer(writer)\r\n        .faultTolerant()\r\n        .skip(IllegalArgumentException.class)\r\n        .skipLimit(10)\r\n        .build();\r\n}\r\n<\/code><\/pre>\n<h3>&#x2705; \u65b9\u6cd52\uff1a\u30ea\u30c8\u30e9\u30a4\u3067\u4e00\u6642\u7684\u306a\u30a8\u30e9\u30fc\u306b\u5099\u3048\u308b<\/h3>\n<pre><code>.retry(DeadlockLoserDataAccessException.class)\r\n.retryLimit(3)\r\n<\/code><\/pre>\n<h3><strong>JobLauncherTestUtils<\/strong>\u3067\u30c6\u30b9\u30c8\u81ea\u52d5\u5316<\/h3>\n<pre><code>@SpringBootTest\r\n@SpringBatchTest\r\nclass MyBatchJobTests {\r\n    @Autowired\r\n    private JobLauncherTestUtils jobLauncherTestUtils;\r\n    @Autowired\r\n    private Job myJob;\r\n\r\n    @Test\r\n    void testMyJob() throws Exception {\r\n        this.jobLauncherTestUtils.setJob(myJob);\r\n        JobExecution jobExecution = jobLauncherTestUtils.launchJob();\r\n        assertEquals(BatchStatus.COMPLETED, jobExecution.getStatus());\r\n    }\r\n}\r\n<\/code><\/pre>\n<hr \/>\n<h2>5. \u5fdc\u7528\u7de8\uff1a\u30de\u30eb\u30c1\u30b9\u30ec\u30c3\u30c9\u51e6\u7406\u30fbSpring Boot 3\u5bfe\u5fdc<\/h2>\n<ul>\n<li><strong>TaskExecutor<\/strong>\u3067Step\u3092\u30de\u30eb\u30c1\u30b9\u30ec\u30c3\u30c9\u5316\u3057\u3001\u3055\u3089\u306b\u9ad8\u901f\u5316\u53ef\u80fd\uff08\u203b<strong>ItemReader<\/strong>\u306f\u30b9\u30ec\u30c3\u30c9\u30bb\u30fc\u30d5\u5fc5\u9808\u306b\u6ce8\u610f\uff09<\/li>\n<li>Spring Boot 3.x\u3067\u306f\u3001<strong>@EnableBatchProcessing<\/strong>\u306f<strong>\u4e0d\u8981<\/strong>\u2192 \u4f9d\u5b58\u8ffd\u52a0\u3067\u81ea\u52d5\u6709\u52b9\u5316\u3055\u308c\u307e\u3059<\/li>\n<\/ul>\n<p>\n    \uff08Spring Boot\u00d7Docker\u306e\u958b\u767a\u74b0\u5883\u69cb\u7bc9\u3084\u30a8\u30e9\u30fc\u5bfe\u7b56\u306b\u3064\u3044\u3066\u306f\u300e<a href=\"https:\/\/route-zero.com\/recruit\/route\/1366\/\" target=\"_blank\" rel=\"noopener\">Docker Compose\u3067\u300cDB\u306b\u7e4b\u304c\u3089\u306a\u3044\uff01\u300d\u3092\u9632\u3050\u3002Spring Boot\u958b\u767a\u306e\u5931\u6557\u30d1\u30bf\u30fc\u30f3\u7dcf\u307e\u3068\u3081<\/a\n    >\u300f\u3082\u3054\u53c2\u7167\u304f\u3060\u3055\u3044\uff09\n  <\/p>\n<blockquote>\n<p><strong>\u7528\u8a9e\u89e3\u8aac\uff1aTaskExecutor<\/strong> \u8907\u6570\u30b9\u30ec\u30c3\u30c9\u3067Step\u3092\u4e26\u5217\u5b9f\u884c\u3059\u308b\u305f\u3081\u306e\u4ed5\u7d44\u307f\u3002\u51e6\u7406\u901f\u5ea6\u5411\u4e0a\u306b\u6709\u52b9\u3060\u304c\u3001\u30b9\u30ec\u30c3\u30c9\u5b89\u5168\u6027\u306b\u6ce8\u610f\u3002<\/p>\n<p><strong>\u7528\u8a9e\u89e3\u8aac\uff1a@Scheduled<\/strong> \u6307\u5b9a\u3057\u305f\u65e5\u6642\u30fb\u5468\u671f\u3067\u30d0\u30c3\u30c1Job\u3092\u81ea\u52d5\u5b9f\u884c\u3059\u308bSpring\u306e\u30a2\u30ce\u30c6\u30fc\u30b7\u30e7\u30f3\u3002<\/p>\n<p><strong>\u7528\u8a9e\u89e3\u8aac\uff1aJobParameters<\/strong> Job\u5b9f\u884c\u6642\u306b\u6e21\u3059\u30d1\u30e9\u30e1\u30fc\u30bf\u3002\u65e5\u6642\u3084ID\u306a\u3069\u3001\u30d0\u30c3\u30c1\u3054\u3068\u306b\u7570\u306a\u308b\u5024\u3092\u6307\u5b9a\u3067\u304d\u308b\u3002<\/p>\n<\/blockquote>\n<h3>Job\u306e\u5b9a\u671f\u5b9f\u884c\u306f<code>@Scheduled<\/code>\uff0bJobParameters\u3067<\/h3>\n<pre><code>@Scheduled(cron = \"0 0 2 * * *\")\r\npublic void launchBatch() {\r\n    JobParameters params = new JobParametersBuilder()\r\n        .addLong(\"time\", System.currentTimeMillis())\r\n        .toJobParameters();\r\n    jobLauncher.run(job, params);\r\n}\r\n<\/code><\/pre>\n<hr \/>\n<h2>\u307e\u3068\u3081<\/h2>\n<ul>\n<li><strong>Job\uff0fStep\uff0fJobRepository<\/strong>\u306e\u95a2\u4fc2\u6027\u3092\u7406\u89e3\u3059\u308c\u3070\u8179\u843d\u3061<\/li>\n<li><strong>Tasklet<\/strong>\uff1a\u5c0f\u30bf\u30b9\u30af\u3001<strong>Chunk<\/strong>\uff1a\u5927\u91cf\u30c7\u30fc\u30bf\u306e\u4e3b\u5f79<\/li>\n<li><strong>Skip\/Retry<\/strong>\u3067\u201c\u6b62\u307e\u3089\u306a\u3044\u201d\u30d0\u30c3\u30c1\u306b<\/li>\n<li><strong>JobLauncherTestUtils<\/strong>\u3067\u81ea\u52d5\u30c6\u30b9\u30c8\u3082\u7c21\u5358<\/li>\n<\/ul>\n<p>\u307e\u305a\u306f\u624b\u5143\u306e\u30d7\u30ed\u30b8\u30a7\u30af\u30c8\u3067\u3001 <strong>\u5b9f\u969b\u306b\u52d5\u304b\u3057\u3066\u307f\u308b\u3053\u3068\u304c\u4e00\u756a\u306e\u8fd1\u9053<\/strong>\u3067\u3059\u3002 \u305c\u3072\u30b3\u30fc\u30c9\u3092\u30b3\u30d4\u30da\u3057\u3066\u3001\u307e\u305a\u306f\u52d5\u304b\u3057\u3066\u307f\u3066\u304f\u3060\u3055\u3044\u3002<\/p>\n<hr \/>\n<\/div>\n","protected":false},"featured_media":1824,"template":"","_links":{"self":[{"href":"https:\/\/route-zero.com\/recruit\/wp-json\/wp\/v2\/route\/1823"}],"collection":[{"href":"https:\/\/route-zero.com\/recruit\/wp-json\/wp\/v2\/route"}],"about":[{"href":"https:\/\/route-zero.com\/recruit\/wp-json\/wp\/v2\/types\/route"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/route-zero.com\/recruit\/wp-json\/wp\/v2\/media\/1824"}],"wp:attachment":[{"href":"https:\/\/route-zero.com\/recruit\/wp-json\/wp\/v2\/media?parent=1823"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}