묻고 답해요
156만명의 커뮤니티!! 함께 토론해봐요.
인프런 TOP Writers
-
미해결스프링 배치
batch 관련 빈들을 proxy 객체로 생성하는 이유가 뭘까요?
안녕하세요batch 관련 빈들을 proxy 객체로 생성하는 이유가 뭘까요?@EnableBatchProcessing 어노테이션에 의해 SimpleBatchConfiguration.java 설정이 적용되는데요!이 설정에서 배치와 관련한 중요 빈들을 생성하는것을 볼 수 있는데* jobRepository* jobLauncher* jobBuilderFactory* stepBuilderFactory궁금한점은 이 빈들에 대해 왜 프록시로(createLazyProxy()) 생성하는걸까요?보통 프록시로 생성되어야 하는 빈들은 빈후처리기에 의해서 필요에 따라 선택되는걸로 알고있거든요아마도, 빈초기화 시점에 BatchConfigurer.class와 과련이 있어 보이는데, 정확히 알지 못하겠습니다.
-
미해결스프링 배치
Xstream 관련 ForbiddenClassException 또는 CannotResolveClassException 해결방법
XStream 버전이 올라가면서 보안 관련 문제로 실습이 제대로 안되는 문제가 있었습니다.간단하게 실습 자체만 하고 싶으신 분들은 XStream 모듈 버전을 낮추시면 됩니다.implementation 'com.thoughtworks.xstream:xstream:1.4.16' 저의 경우 그렇게 하기는 싫어서 다른 방식으로 문제를 해결했습니다. public Unmarshaller itemUnmarshaller() { final Map<String, Class<?>> aliases = new HashMap<>(); aliases.put("customer", Customer.class); aliases.put("id", Long.class); aliases.put("name", String.class); aliases.put("age", Integer.class); final XStreamMarshaller xStreamMarshaller = new XStreamMarshaller(); final XStream stream = xStreamMarshaller.getXStream(); stream.alias("customer", Customer.class); // CannotResolveClassException 해결방안 stream.addPermission(AnyTypePermission.ANY); // ForbiddenClassException 해결방안 xStreamMarshaller.setAliases(aliases); return xStreamMarshaller; }와 같이 진행했을 때 저의 경우 문제 없이 작동했습니다.
-
미해결스프링 배치
안녕하세요
안녕하세요job parameter로 seq(long) 타입을 인식을 못해서 Null Pointer exception이 나고 있네요 Mac에서 zsh 쓰고있는데 혹시 저같은 분 계실까요?
-
미해결스프링 배치
firstPageSql, NamedParameterJdbcTemplate null 로 들어가는데 왜그럴까요..
(사진)
-
미해결스프링 배치
동일한 JobInstance에 대해서는 JobExecution이 복사가 되나요?
안녕하세요? 공유자님의 강의 잘 보고 있습니다 스프링 배치 도메인 이해 - ExecutionContext 영상의 41:46부분을 보면 jobInstance는 하나이지만 JobExecution은 똑같은 데이터로 로우가 하나 더 생겼습니다.이같은 경우는 jobExecution2가 jobExecution1의 데이터를 기반으로 실행되고 DB에 복제되어 저장되었다고 보는게 맞을까요?
-
해결됨스프링 배치
빌드된 jar 파일로 jobParameter를 전달할 경우 DB
빌드된 jar 파일로 jobParameter를 전달할 경우 DB에 Parameter값이나 Job실행 정보들을 남기지 않는데 맞는건가요? 아니면 어떠한 설정 값 영향인가요?
-
미해결스프링 배치
빌드된 jar 파일로 jobParameter를 전달할 때 zsh 사용 시 no matches found
제 환경은 Mac에 Zsh을 설치하여 사용하고 있는데 위와 같은 에러가 발생하는 문제가 존재하였습니다. 해당 문제는 간단하게 해결할 수 있습니다. JobParmeters로 넘길 인자를 따옴표(')로 감싸서 던지면 해결됨을 확인할 수 있습니다. 이런 식으로 정상적으로 나옴을 확인할 수 있었습니다. 동일한 문제가 발생한 분들 참고하시면 도움이 되실 것 같습니다.
-
미해결스프링 배치
jobLauncherTestUtils 빨간 줄 질문입니다.
jobLauncherTestUtils에 강의에서도 보면 빨간 밑줄표시가 되어 있는데요Could not autowire. No beans of 'JobLauncherTestUtils' type found경고 문구를 보면 위에처럼 해당 타입의 빈을 찾을수 없다는 표시인데 실행하면 잘 되더라구요.. 그냥 무시하기에는 찝찝해서 왜 이런건지 혹시 알 수 있을까요?
-
미해결스프링 배치
실무에서 이런 요건의 배치를 구성할 경우
안녕하세요 강사님.. 아래의 경우 spring batch 구성의 best practice 가 궁금합니다. - 배치 로딩 시간 > 스케줄 재실행 시간 - 외부 트리거(DB 데이터 insert 등) 에 의해 바로바로 배치가 실행되어야 하는 경우 감사합니다.
-
미해결스프링 배치
@StepScope + JpaItemReader에서 EntityManager Null Pointer exception 발생 문제 도와주세요!
안녕하세요, 강사님. 항상 좋은 강의 제공해주셔서 감사합니다. 다름이 아니라 이번에 강사님 강의 보고 복습하던 도중에 문제가 발생해서 해결 방법이 있을까 해서 여쭤보려고 글을 작성했습니다. 파티셔닝 Step을 생성해서 처리하는 것을 따라해보고 있는데, 강사님께서는 ItemReader를 Jdbc 계열로 사용하셨는데, 저는 JPA를 선호해서 JPAItemReader를 사용했습니다. 먼저 단위 테스트를 위해 @StepScope 없이 JPAItemReader를 사용할 경우, 문제 없이 동작하는 것을 확인했습니다. 그런데 JpaItemReader에 @StepScope를 다는 순간 Null Pointer Exception이 발생하는 것을 확인했습니다. 처음에는 JpaItemReader가 Proxy Bean으로 주입이 안되는가? 라고 생각을 했었는데, 디버그 모드를 타고 가보니 다음과 같은 위치에서 문제가 있는 것을 확인했습니다. 프록시 객체에 타겟 객체는 정상적으로 주입을 해주는데, 문제는 타겟 객체인 JpaItemReader에 entityManager가 null이기 때문에 Reader를 하는 과정에서 문제가 있다는 것을 알게 되었습니다. EntityManager는 위에서 볼 수 있듯이 doOpen() step에서 제공해주는 것으로 보이는데, doOpen() Step을 거치지 않아 문제가 있는 것 같습니다. 조금 더 확인해보니 AbstractStep의 Open 메서드에 전달되는 ItemStream의 Size가 0인 것을 보니... 이것에 대해 문제가 있는 것 같습니다. 혹시 이처럼 JpaItemReader에서 @StepScope로 사용 시, EntityManager가 주입되지 않는 경우는 어떻게 해결해야 할까요? 아래는 제가 PartitionStep을 구성하기 전에 각각의 ItemReader, ItemWriter, ItemProcessor에서 @StepScope가 정상적으로 동작하는지 확인하기 위해 작성한 코드이고, 이 코드를 돌릴 때 문제가 발생하는 것을 확인했습니다. package io.springbatch.springbatchlecture.retry.partitioning;import io.springbatch.springbatchlecture.dbitemreader.Customer;import io.springbatch.springbatchlecture.dbwriter.Customer2;import lombok.RequiredArgsConstructor;import org.springframework.batch.core.Job;import org.springframework.batch.core.Step;import org.springframework.batch.core.configuration.annotation.JobBuilderFactory;import org.springframework.batch.core.configuration.annotation.StepBuilderFactory;import org.springframework.batch.core.configuration.annotation.StepScope;import org.springframework.batch.core.launch.support.RunIdIncrementer;import org.springframework.batch.core.partition.support.Partitioner;import org.springframework.batch.core.partition.support.SimplePartitioner;import org.springframework.batch.item.ItemProcessor;import org.springframework.batch.item.ItemReader;import org.springframework.batch.item.ItemWriter;import org.springframework.batch.item.database.JdbcPagingItemReader;import org.springframework.batch.item.database.Order;import org.springframework.batch.item.database.builder.JdbcBatchItemWriterBuilder;import org.springframework.batch.item.database.builder.JdbcPagingItemReaderBuilder;import org.springframework.batch.item.database.builder.JpaPagingItemReaderBuilder;import org.springframework.beans.factory.annotation.Value;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;import org.springframework.core.task.SimpleAsyncTaskExecutor;import javax.persistence.EntityManagerFactory;import javax.sql.DataSource;import java.util.HashMap;import java.util.concurrent.atomic.AtomicLong;@Configuration@RequiredArgsConstructorpublic class SimpleTestConfig { private final JobBuilderFactory jobBuilderFactory; private final StepBuilderFactory stepBuilderFactory; private final EntityManagerFactory emf; private final DataSource dataSource; private AtomicLong myId = new AtomicLong(); @Bean public Job batchJob200() { return jobBuilderFactory.get("partitioningJob") .incrementer(new RunIdIncrementer()) .start(slaveStep()) .build(); } @Bean public Step slaveStep() { return stepBuilderFactory.get("slaveStepMaster") .<Customer, Customer2>chunk(1000)// .reader(pagingItemReader()) .reader(batchReader()) .writer(batchWriter()) .processor(batchProcessor()) .build(); } @Bean @StepScope public ItemProcessor<? super Customer, ? extends Customer2> batchProcessor() { System.out.println("itemProcessor Here"); return (ItemProcessor<Customer, Customer2>) item -> Customer2.builder() .id(myId.incrementAndGet()) .birthDate(item.getBirthDate()) .firstName(item.getFirstName()) .lastName(item.getLastName()) .build(); } @Bean @StepScope public ItemWriter<? super Customer2> batchWriter() { return new JdbcBatchItemWriterBuilder<Customer2>() .sql("INSERT INTO Customer2(customer2_id, birth_date, first_name, last_name) values (:id, :birthDate, :firstName, :lastName)") .dataSource(dataSource) .beanMapped() .build(); } @Bean @StepScope public ItemReader<? extends Customer> batchReader() { return new JpaPagingItemReaderBuilder<Customer>() .name("partitionStepJpaReader") .currentItemCount(0) .entityManagerFactory(emf) .maxItemCount(1000) .queryString("select c from Customer c") .build(); } @Bean @StepScope // 앞쪽 강의 봐야함. public JdbcPagingItemReader<Customer> pagingItemReader() { System.out.println("Target Created"); HashMap<String, Order> sortKeys = new HashMap<>(); sortKeys.put("customer_id", Order.ASCENDING); return new JdbcPagingItemReaderBuilder<Customer>() .name("pagingBuilder") .dataSource(dataSource) .fetchSize(1000) .beanRowMapper(Customer.class) .selectClause("customer_id, first_name, last_name, birth_date") .fromClause("from customer")// .whereClause("where customer_id >= " + minValue + " and customer_id <= " + maxValue) .sortKeys(sortKeys) .build(); } @Bean public Partitioner partitioner() { SimplePartitioner simplePartitioner = new SimplePartitioner(); simplePartitioner.partition(4); return simplePartitioner; }}
-
미해결스프링 배치
배치 작업 도중 실패할때
안녕하세요 강의 잘 보고있습니다. 데이터가 100개 있고, 청크 사이즈가 10이라고 할 때 0~9, 10 ~ 19 까지 성공하고 애플리케이션 문제 등으로 프로그램이 종료 혹은 실패가 되었을 때, 다시 0번부터 실행 안 하고, 20번 부터 실행을 하려면 어떻게 해야될까요? 몇번부터 몇번까지 실행했는지 기록하는 메타데이터용 테이블을 만들어서 기록해야되는 거 말고는 없나요?? (예를 들어 실패했을때 다시 실행하면, 실패한 곳부터 알아서 스프링 배치가 실행해주는..)
-
미해결스프링 배치
docker db (mysql) 이 죽는 현상이 있습니다.
안녕하세요. 좋은 강의 만들어주셔서 감사합니다. 아래와 같이 강좌와 유사하게 spring.datasource.hikari 로 mysql 설정을 한 후 간단한 job 을 실행시키면 docker 로 설치한 mysql db 가 죽는 현상이 있습니다. 혹시 hikari 설정이 부족해서 그런 것일까요? 강좌에서는 잘 진행이 되는것 같아서 질문드립니다. 그래서 주석 처리하고 기존에 하던 방식으로 spring.datasource 를 이용해서 mysql 설정을 했습니다. spring.datasoruce 는 datasource 설정인거 같고, spring.datasource.hikari 는 hikari connection pool 설정인거 같은데요. 헷갈리네요. 어디에 db 설정을 정의하는것이 기본일까요? spring: profiles: active: local---spring: config: activate: on-profile: local datasource:# hikari:# jdbc-url: jdbc:mysql://av-api01-dc.nfra.io:23306/aida_project?useUnicode=true&characterEncoding=utf8# username: root# password: root# driver-class-name: com.mysql.cj.jdbc.Driver url: jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf8 username: root password: root driver-class-name: com.mysql.cj.jdbc.Driver batch: jdbc: initialize-schema: always
-
미해결스프링 배치
EXITE_CODE 질문드립니다.
챕터 : 스프링 배치 실행 - flow강의명 : SimpleFlow 예제 해당 강의 13:59 부터 이해가 잘안되고 있습니다. flow1()의 step2에서 예외가 발생하면서 STEP_EXCUTION의 EXITE_CODE가 FAILED이므로flow3()을 실행했고이후 flow3() 그에 해당하는 모든 스탭이 COMPLETED인데 왜 JOB_EXCUTION의 EXITE_CODE가 FAILED가 되는걸까요?
-
미해결스프링 배치
JdbcCursorItemReader 쿼리 실행 시점과 ResultSet 동작 방식이 궁금합니다.
안녕하세요. AbstractCursorItemReader#doOpen() -> JdbcCursorItemReader#openCursor()에서 ......this.rs = preparedStatement.executeQuery();...... 해당 시점에 쿼리가 실행이 되고, 이후 커넥션을 쭉 유지한채 AbstractCursorItemReader#doRead() -> JdbcCursorItemReader#readCursor(rs, currentRow)가 메소드가 호출될 때마다 DB에서 1row씩 데이터를 꺼내오는 방식으로 동작하는 것일까요? openCursor에서 쿼리 실행 후 메모리에 쿼리 수행결과를 가지고 있다가 doRead() -> readCursor()를 수행하는건지 혼란이 와서 질문 드립니다. JpaCursorItemReader의 경우는 JpaCursorItemReader#doOpen()에서 쿼리 실행 후 결과를 메모리에 가지고 있다가 이때는 DB 커넥션 유지하지 않고, doRead() 호출시 한로우씩 반환하는 식으로 동작하는게 맞나요?
-
미해결스프링 배치
Spring batch + mybatis는 사용이 불가한지 궁금합니다.
Spring batch + mybatis는 사용이 불가한지 궁금합니다.
-
해결됨스프링 배치
EXIT_CODE 반영 문의
안녕하세요 강사님 한가지 궁금한게 있어 문의 남깁니다 flow1에서 failed 시점에 flow3으로 흐르도록 했을 때 flow3의 모든 스탭이 성공하여서 제 생각으로는 JobExecution 기록에 EXIT_CODE가 COMPLETED로 기록될 줄 알았는데 JobExecution 기록에 EXIT_CODE 가 FAILED로 기록되어 있습니다. JobExecution의 EXIT_CODE가 마지막 스탭이나 플로우의 상태값을 반영되는 것으로 인지하고 있었는데 위와 같은 경우와 같이 Job의 과정중 하나의 스탭이라도 실패하게 된다면 EXIT_CODE에는 FAILED로 기록이 되는건가요?