묻고 답해요
141만명의 커뮤니티!! 함께 토론해봐요.
인프런 TOP Writers
-
미해결스프링 배치
멀티스레드 환경에서의 트랜잭션 및 lock 관련 질문드립니다.
- 학습 관련 질문을 남겨주세요. 상세히 작성하면 더 좋아요! - 먼저 유사한 질문이 있었는지 검색해보세요. - 서로 예의를 지키며 존중하는 문화를 만들어가요. - 잠깐! 인프런 서비스 운영 관련 문의는 1:1 문의하기를 이용해주세요. 안녕하세요 강사님! 강의를 듣고 정말 많은 도움을 받고 있습니다! 멀티스레드 환경 부분을 듣고 직접 이것저것 해보면서 몇가지 질문 사항이 있습니다. 1) 트랜잭션 스프링 배치에서 시작하는 트랜잭션 외에 ItemProcessor에서 다른 service(@Transactional)를 호출하여 데이터 처리를 하게 되는 경우 앞서서 배치가 생성해놓은 트랜잭션에 함께 포함되는 것이 아니라 별도로 트랜잭션이 열리게 된다는 다른 질문의 답변을 보았습니다! 그렇다면 배치의 트랜잭션이 끝나는 시점이 서비스 트랜잭션이 끝나는 시점과 다를텐데요. 이 때 배치의 트랜잭션이 종료되는 시점은 service처리가 다 이후 write처리까지 다 끝난 이후 인지, service 트랜잭션의 종료와는 상관 없이 트랜잭션이 종료 되게 되는 것인지 궁금합니다. + 트랜잭션의 종료 시점이 다르게 될 경우 발생될 수 있는 문제들은 어떻게 처리하게되는 걸까요?(배치를 돌릴때 최대한 다른 트랜잭션을 열면 안되는 것인지 궁금합니다!) ( org.hibernate.LazyInitializationException : failed to lazily initialize a collection of role 예외, 트랜잭션을 닫을 시점에 entity manger is null (AbstractItemCountingItemStreamItemReader.close)예외가 발생하였는데 이것과 관련되어있는지도 궁금합니다...!)2) 멀티스레드 환경의 chunk 배치 멀티스레드 환경에서 chunk 배치를 사용하는 경우 JpaPagingItemReader를 사용한다고 가정하였을때, '스레드 동기화를 보장'한다는 것에 대해 궁금한데요. 예를 들어, 쓰레드가 5개인 환경에서 조회할 값이 isSample 컬럼이 false인 데이터 100개라고 가정하고 pagingItemReader를 이용해서 offset을 0으로 두고 10개씩 (chunksize = 10, pageSize = 10) 읽고 processor가 isSample 컬럼을 true로 바꾸는 역할을 수행하는 것을 가정합니다. 먼저 1~10번의 아이템을 각각의 1~5번의 스레드가 10개의 각각의 아이템을 할당 받는 과정에서 동기화(중복된 아이템을 스레드가 겹쳐서 읽지 않음)를 이루고 처리후 다음 10개를 읽고 처리하는 과정을 반복한다고 이해하였는데요. 이때, 만약 처음 1~10번의 아이템을 읽고 처리하는 과정에서 한 스레드가 처리과정에서 오랜 시간이 소요되는 병목지점이 발생한다면 commit이 이루어지지 않고, 다음 아이템 11~20번을 읽을때 앞서서 처리되지 않은 아이템을 다시 읽어오고 또다시 병목 지점이 발생할 수도 있고, 결과적으로 같은 아이템을 다른 스레드가 중복으로 처리하게 될 수도 있을 텐데 이럴경우 어떻게 처리가 이루어지는지 궁금합니다. (이런 부분에서는 동기화가 이루어지지 않는 것인지, 제가 이해한 과정이 맞는지도 궁금합니다...!) 3) synchronizeditemstreamreader를 사용하는 경우 lockSynchronizedItemStreamReader를 사용하는 경우에는 동기화를 위해서 쓰레드가 lock을 획득하고 처리하는 과정이 이루어진다면, DB connection의 갯수는 항상 쓰레드의 갯수보다 많게 유지해야 하는 걸까요? ( 작게하면 Connection is not available, request timed out after 오류가 뜨고 있습니다...!)강의 정말 잘 보고 있습니다! 감사합니다 강사님!
-
미해결스프링 배치
젠킨스 스케줄
안녕하세요.실무 코드만 보고 배치를 만들다가 제대로 이해하고 써보자는 생각에 강의를 듣게 되었는데 제대로 배우고 있어서 너무 유익하게 보고 있습니다.ㅎㅎ제가 아직은 배치를 깊이 있게 아는 것은 아니라 기본적인 질문일 수도 있지만.. 실무에서 젠킨스 스케줄 설정을 통해 같은 파라미터의 Job 을 매 시간마다 실행시키고 있습니다.그런데 동일한 Job + JobParameter 의 경우 재실행이 불가능한 것으로 배우고 있는데, 젠킨스 스케줄의 경우에는 예외인걸까요!?(incrementer() 없이 단순한 start(), next() 구성의 배치입니다.)
-
미해결스프링 배치
롤백 관련 질문드립니다.
여러 스탭을 포함한 Job을 실행하는 과정에서 Job이 실패하면 실패하기 전까지는 커밋이 되는데, 그게 아니라 Job이 실패하면 Job이 실행하시 전으로 롤백할 수도 있나요?
-
미해결스프링 배치
트랜잭션 관련 질문드립니다.
- 학습 관련 질문을 남겨주세요. 상세히 작성하면 더 좋아요! - 먼저 유사한 질문이 있었는지 검색해보세요. - 서로 예의를 지키며 존중하는 문화를 만들어가요. - 잠깐! 인프런 서비스 운영 관련 문의는 1:1 문의하기를 이용해주세요. 안녕하세요, 이전에 트랜잭션 범위 질문 관련하여 추가 질문드리려고 합니다 :) 단일 tasklet에서 여러 테이블을 update할 때 하나를 업데이트하고 뒤에서 오류가 나면 롤백이 안되는데 보통 실무에서 어떻게 사용하는지 궁금합니다.예를 들면 아래와 같이 하나의 tasklet 내에서 2개의 업데이트 작업이 필요하고, 이 두 테이블 업데이트가 하나의 트랜잭션에 묶여야 할 때 어떤식으로 작업을 주로 하는지 궁금합니다.new tasklet() { // 테이블1 업데이트 로직 table1Service.update(); // 오류 발생 throw new RuntimeException("오류 발생"); // 테이블2 업데이트 로직 table2Service.update(); }(chunk 단위로 업데이트할 정도로 업데이트할 양이 많지 않아 따로 itemReader/itemProcess/itemWriter 구현을 하지 않은 단일 tasklet 예시입니다)그리고, 테이블 업데이트 로직이 다른 서비스 로직을 호출하여서 업데이트하는것이라면 해당 서비스 로직의 transaction에 springbatch가 만들어준 transaction이 전파되지 않는 이유가 궁금합니다. step 실행을 함으로써 springbatch가 생성해준 트랜잭션 내부에서 서비스를 호출하여서 해당 트랜잭션이 전파되어서 서비스의 트랜잭션이 자식 트랜잭션이 될 것이라 생각하였는데, 실제로 테스트했을 때 각각 따로 트랜잭션 처리가 되어 롤백이 제대로 이루어지지 않는 것으로 보여서 문의드립니다.
-
미해결스프링 배치
Fetch와 Cursor의 순서?
[DB - Cursor & Paging 이해] 강의에서 보여주신 장표를 보면 cursot가 먼저 움직이고 fetch를 통해 application으로 매핑된 데이터(객체)를 넘겨주는 것처럼 표현되어있는데요.fetch size에 의해서 DB --> 메모리로 데이터가 적재된 후, 그 결과집합을 순차적으로 cursor를 통해 접근하는걸로 알고있습니다.즉, fetch size는 DB에서 메모리로 데이터를 적재할 크기이고 그 데이터 셋을 처음부터 cursor를 통해 접근하는게 맞지않나 싶어서 질문드립니다. 제가 반대로 알고 있을 수 있지만...
-
미해결스프링 배치
Flow 생성 시, flowBuilder에 end()와 build()를 각각 호출하는 이유
- 학습 관련 질문을 남겨주세요. 상세히 작성하면 더 좋아요! - 먼저 유사한 질문이 있었는지 검색해보세요. - 서로 예의를 지키며 존중하는 문화를 만들어가요. - 잠깐! 인프런 서비스 운영 관련 문의는 1:1 문의하기를 이용해주세요.안녕하세요, FlowJob 관련하여서 궁금한 점이 있어 문의드립니다.강의 중에 아래와 같이 작성된 코드가 있었는데요. @Bean public Flow flow() { FlowBuilder<Flow> flowBuilder = new FlowBuilder<>("flow"); flowBuilder.start(step1()) .next(step2()) .end(); return flowBuilder.build(); }FlowBuilder 내 end() 메소드를 살펴보면, end() 메소드 내에서 this.build()를 호출하는 것으로 보이는데요. public final Q end() { return this.build(); } 하기와 같이 작성하지 않고 위처럼 end()와 build()를 각각 쓰는 사유가 있는지 궁금합니다.@Bean public Flow flow() { FlowBuilder<Flow> flowBuilder = new FlowBuilder<>("flow"); return flowBuilder.start(step1()) .next(step2()) .end(); } 새해 복 많이 받으세요 :)
-
미해결스프링 배치
v5는 많은 것이 바뀌어서 test해보려는데 왜 Tasklet에 있는 System.out.println는 실행되지 않을까요??
v5로 test해보려는데 왜 Tasklet의 System.out.println는 찍히지 않는 걸까요??package me.victorsung.demobatch; import org.springframework.batch.core.Job; import org.springframework.batch.core.Step; import org.springframework.batch.core.StepContribution; import org.springframework.batch.core.configuration.support.DefaultBatchConfiguration; import org.springframework.batch.core.job.builder.JobBuilder; import org.springframework.batch.core.repository.JobRepository; import org.springframework.batch.core.scope.context.ChunkContext; import org.springframework.batch.core.step.builder.StepBuilder; import org.springframework.batch.core.step.tasklet.Tasklet; import org.springframework.batch.repeat.RepeatStatus; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.transaction.PlatformTransactionManager; @Configuration public class HelloJobConfiguration extends DefaultBatchConfiguration { @Bean public Job myJob(JobRepository jobRepository, Step myStep1, Step myStep2) { System.out.println("this is job"); return new JobBuilder("myJob", jobRepository) .start(myStep1) .next(myStep2) .build(); } @Bean public Step myStep1(JobRepository jobRepository, Tasklet myTasklet1, PlatformTransactionManager transactionManager) { System.out.println("this is step1"); return new StepBuilder("myStep1", jobRepository) .tasklet(myTasklet1, transactionManager) .build(); } @Bean public Step myStep2(JobRepository jobRepository, Tasklet myTasklet2, PlatformTransactionManager transactionManager) { System.out.println("this is step2"); return new StepBuilder("myStep2", jobRepository) .tasklet(myTasklet2, transactionManager) .build(); } @Bean public Tasklet myTasklet1() { System.out.println( """ this is myTasklet1 """ ); // Step에서는 Tasklet을 무한 반복 시킨다. 그래서 RepeatStatus을 null || RepeatStatus.FINISHED로 주어야 한번 실행하고 끝난다. return new Tasklet() { @Override public RepeatStatus execute(StepContribution contribution, ChunkContext chunkContext) throws Exception { System.out.println( """ myTasklet1 ============================================== >> contribution = %s >> chunkContext = %s ============================================== """.formatted(contribution, chunkContext) ); return RepeatStatus.FINISHED; } }; } @Bean public Tasklet myTasklet2() { System.out.println("this is taskLet2"); // Step에서는 Tasklet을 무한 반복 시킨다. 그래서 RepeatStatus을 null || RepeatStatus.FINISHED로 주어야 한번 실행하고 끝난다. return (contribution, chunkContext) -> { System.out.println("test2"); System.out.println( """ myTasklet2 ============================================== >> contribution = %s >> chunkContext = %s ============================================== """.formatted(contribution, chunkContext) ); return RepeatStatus.FINISHED; }; } } . ____ _ __ _ _ /\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \ ( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \ \\/ ___)| |_)| | | | | || (_| | ) ) ) ) ' |____| .__|_| |_|_| |_\__, | / / / / =========|_|==============|___/=/_/_/_/ :: Spring Boot :: (v3.0.0) 2022-12-06T11:11:34.542+09:00 INFO 87250 --- [ main] m.v.demobatch.DemoBatchApplication : Starting DemoBatchApplication using Java 17.0.4.1 with PID 87250 (/Users/victor/Documents/thecommerce/demo-batch/out/production/classes started by victor in /Users/victor/Documents/thecommerce/demo-batch) 2022-12-06T11:11:34.544+09:00 INFO 87250 --- [ main] m.v.demobatch.DemoBatchApplication : No active profile set, falling back to 1 default profile: "default" 2022-12-06T11:11:34.671+09:00 INFO 87250 --- [ main] o.s.b.c.c.annotation.BatchRegistrar : Bean jobRepository already defined in the application context, skipping the registration of a jobRepository 2022-12-06T11:11:34.671+09:00 INFO 87250 --- [ main] o.s.b.c.c.annotation.BatchRegistrar : Bean jobExplorer already defined in the application context, skipping the registration of a jobExplorer 2022-12-06T11:11:34.671+09:00 INFO 87250 --- [ main] o.s.b.c.c.annotation.BatchRegistrar : Bean jobLauncher already defined in the application context, skipping the registration of a jobLauncher 2022-12-06T11:11:34.671+09:00 INFO 87250 --- [ main] o.s.b.c.c.annotation.BatchRegistrar : Bean jobRegistry already defined in the application context, skipping the registration of a jobRegistry 2022-12-06T11:11:34.671+09:00 INFO 87250 --- [ main] o.s.b.c.c.annotation.BatchRegistrar : Bean jobOperator already defined in the application context, skipping the registration of a jobOperator 2022-12-06T11:11:34.671+09:00 INFO 87250 --- [ main] o.s.b.c.c.annotation.BatchRegistrar : Finished Spring Batch infrastructure beans configuration in 0 ms. 2022-12-06T11:11:34.784+09:00 WARN 87250 --- [ main] ocalVariableTableParameterNameDiscoverer : Using deprecated '-debug' fallback for parameter name resolution. Compile the affected code with '-parameters' instead or avoid its introspection: me.victorsung.demobatch.HelloJobConfiguration 2022-12-06T11:11:34.811+09:00 INFO 87250 --- [ main] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Starting... 2022-12-06T11:11:34.891+09:00 INFO 87250 --- [ main] com.zaxxer.hikari.pool.HikariPool : HikariPool-1 - Added connection conn0: url=jdbc:h2:mem:06a2d6ef-e350-45b8-8468-33c43eb10333 user=SA 2022-12-06T11:11:34.891+09:00 INFO 87250 --- [ main] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Start completed. this is myTasklet1 this is step1 2022-12-06T11:11:34.922+09:00 INFO 87250 --- [ main] .c.a.BatchObservabilityBeanPostProcessor : No Micrometer observation registry found, defaulting to ObservationRegistry.NOOP this is taskLet2 this is step2 2022-12-06T11:11:34.923+09:00 INFO 87250 --- [ main] .c.a.BatchObservabilityBeanPostProcessor : No Micrometer observation registry found, defaulting to ObservationRegistry.NOOP this is job 2022-12-06T11:11:34.925+09:00 INFO 87250 --- [ main] .c.a.BatchObservabilityBeanPostProcessor : No Micrometer observation registry found, defaulting to ObservationRegistry.NOOP 2022-12-06T11:11:34.985+09:00 INFO 87250 --- [ main] m.v.demobatch.DemoBatchApplication : Started DemoBatchApplication in 0.659 seconds (process running for 0.901) 2022-12-06T11:11:34.988+09:00 INFO 87250 --- [ionShutdownHook] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Shutdown initiated... 2022-12-06T11:11:34.990+09:00 INFO 87250 --- [ionShutdownHook] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Shutdown completed. Process finished with exit code 0
-
미해결스프링 배치
강의자료 문의드립니다.
안녕하세요. 제가 MAC을 사용해서요.강의자료 PDF로도 혹시 제공 가능한가요. ㅠㅠ 감사합니다.
-
미해결스프링 배치
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