스프링 프레임워크/springbatch

spring batch 시작하기

blogger903 2024. 7. 31. 08:07
728x90

환경

IDE: intellij
SpringBootVersion: 3.0.11
Gradle: 8.8
Java: 17

 

build.gradle.kts

import org.jetbrains.kotlin.gradle.tasks.KotlinCompile

plugins {
    id("org.springframework.boot") version "3.0.11"
    id("io.spring.dependency-management") version "1.1.0"
    kotlin("jvm") version "1.7.22"
    kotlin("plugin.spring") version "1.7.22"
    kotlin("plugin.jpa") version "1.7.22"
}

group = "com.example"
version = "0.0.1-SNAPSHOT"
java.sourceCompatibility = JavaVersion.VERSION_17

repositories {
    mavenCentral()
}

dependencies {
    implementation("org.springframework.boot:spring-boot-starter-data-jpa")
    implementation("org.springframework.boot:spring-boot-starter-web")
    implementation("org.springframework.boot:spring-boot-starter-batch")
    implementation("org.jetbrains.kotlin:kotlin-reflect")
    implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8")
    implementation("org.springframework.kafka:spring-kafka:3.2.0")
    implementation("mysql:mysql-connector-java:8.0.33")
    implementation("com.querydsl:querydsl-jpa:5.0.0:jakarta")
    implementation("com.querydsl:querydsl-kotlin:5.0.0")

    annotationProcessor("com.querydsl:querydsl-apt:5.0.0:jakarta")

    testImplementation("org.springframework.boot:spring-boot-starter-test")
    testImplementation("org.springframework.batch:spring-batch-test")
    testImplementation("org.junit.jupiter:junit-jupiter-api")
    testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine")
}

tasks.withType<KotlinCompile> {
    kotlinOptions {
        freeCompilerArgs = listOf("-Xjsr305=strict")
        jvmTarget = "17"
    }
}

tasks.withType<Test> {
    useJUnitPlatform()
}

엔티티 생성, Repository생성

import jakarta.persistence.Entity
import jakarta.persistence.GeneratedValue
import jakarta.persistence.GenerationType
import jakarta.persistence.Id

@Entity
data class House(
    @Id @GeneratedValue(strategy = GenerationType.IDENTITY)
    val id: Long? = null,
    val address: String,
    val price: Double
)
import com.example.kotlinsimplespringbatch.domain.House
import org.springframework.data.jpa.repository.JpaRepository
import org.springframework.stereotype.Repository

@Repository
interface HouseRepository : JpaRepository<House, Long>

job 생성

import com.example.kotlinsimplespringbatch.adapter.repository.HouseRepository
import com.example.kotlinsimplespringbatch.domain.House
import org.springframework.batch.core.Job
import org.springframework.batch.core.Step
import org.springframework.batch.core.job.builder.JobBuilder
import org.springframework.batch.core.repository.JobRepository
import org.springframework.batch.core.step.builder.StepBuilder
import org.springframework.batch.repeat.RepeatStatus
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import org.springframework.transaction.PlatformTransactionManager

@Configuration
class HouseCreationJobConfig(
    val jobRepository: JobRepository,
    val transactionManager: PlatformTransactionManager,
    val houseRepository: HouseRepository
) {

    @Bean
    fun houseCreationJob(houseCreationStep: Step): Job {
        return JobBuilder("houseCreationJob", jobRepository)
            .start(houseCreationStep)
            .build()
    }

    @Bean
    fun houseCreationStep(): Step {
        return StepBuilder("houseCreationStep", jobRepository)
            .tasklet({ contribution, chunkContext ->
                val houses = (1..100).map { index ->
                    House(
                        address = "Address $index",
                        price = (Math.random() * 1000000 + 100000)
                    )
                }
                houseRepository.saveAll(houses)
                RepeatStatus.FINISHED
            }, transactionManager)
            .build()
    }
}

docker-compose.yml

version: '3.8'

services:
  mysql:
    container_name: kotlin-batch-mysql
    image: mysql:8.0.33
    platform: linux/arm64
    restart: always
    environment:
      MYSQL_ROOT_HOST: '%'
      MYSQL_ROOT_PASSWORD: 'house'
      MYSQL_USER: 'house'
      MYSQL_PASSWORD: 'house'
      MYSQL_DATABASE: 'house'
      TZ: 'Asia/Seoul'
    ports:
      - '3313:3306'
    command:
      - --character-set-server=utf8mb4
      - --collation-server=utf8mb4_unicode_ci
      - --default-authentication-plugin=mysql_native_password

schema-mysql.sql 실행

External library
org.springframework.batch/spring-batch-core:5.0.3 > spring-batch-core-5.0.3.jar > org/springframework/batch/core/schema-mysql.sql

application.yml 설정

맨위에 기본 환경변수를 적용해주고 spring.batch.job.name을 job.name이 없을경우 NONE을 해줘야 job.name이 명시되지 않으면 아무런 job이 실행되지 않습니다

spring:
  application:
    name: kotlin-simple-spring-batch
  profiles:
    active: local
  batch:
    job:
      name: ${job.name:NONE}

---
spring:
  config:
    activate:
      on-profile: local
  datasource:
    url: jdbc:mysql://localhost:3313/house?serverTimezone=Asia/Seoul&characterEncoding=UTF-8
    username: house
    password: house
    driver-class-name: com.mysql.cj.jdbc.Driver
  jpa:
    show-sql: true
    generate-ddl: false
    hibernate:
      ddl-auto: none
  batch:
    jdbc:
      initialize-schema: never
---
spring:
  config:
    activate:
      on-profile: test
  jpa:
    show-sql: true
    database-platform: org.hibernate.dialect.H2Dialect
    hibernate:
      ddl-auto: update
  batch:
    jdbc:
      initialize-schema: always

ide로 vm option, program option 적용

 

 

 

springboot main

 

Spring Batch 5와 Spring Boot 3.0 이상을 사용할 경우:

  1. spring-boot-starter-batch 의존성만 추가하면 됩니다.
  2. Spring Boot가 자동으로 필요한 Spring Batch 인프라 빈들을 구성합니다.
  3. @EnableBatchProcessing 어노테이션은 더 이상 필요하지 않습니다.
import org.springframework.boot.autoconfigure.SpringBootApplication
import org.springframework.boot.runApplication

@SpringBootApplication
class KotlinSimpleSpringBatchApplication

fun main(args: Array<String>) {
    runApplication<KotlinSimpleSpringBatchApplication>(*args)
}

 

참고: https://arc.net/l/quote/akqsogtk