묻고 답해요
156만명의 커뮤니티!! 함께 토론해봐요.
인프런 TOP Writers
-
미해결스프링 배치
spring batch 트랜잭션 질문입니다.
아래 설명해주신것처럼 스프링배치에서 외부에서 @Transactional 을 쓰는것을 허용하지 않는다는것을 확인했습니다.https://brunch.co.kr/@anonymdevoo/50여기를보고 semaphore.acquire를 하고 외부 트랜잭션이 끝나지 않아서 afterCompletion에서 해당 semaphore.release를 호출하지 못한다는것을 확인하였습니다.하지만 아래처럼@RequiredArgsConstructor @Configuration public class TaskletStepConfiguration { private final JobBuilderFactory jobBuilderFactory; private final StepBuilderFactory stepBuilderFactory; @Bean public Job batchJob() { return this.jobBuilderFactory.get("batchJob") .incrementer(new RunIdIncrementer()) .start(taskStep()) .next(chunkStep()) .build(); } @Bean @Transactional public Step taskStep() { return stepBuilderFactory.get("taskStep") .tasklet((contribution, chunkContext) -> { System.out.println("step1 has executed"); return RepeatStatus.FINISHED; }) .build(); } @Bean @Transactional public Step chunkStep() { return stepBuilderFactory.get("chunkStep") .<String, String>chunk(3) .reader(new ListItemReader(Arrays.asList("item1","item2","item3"))) .processor(new ItemProcessor<String, String>() { @Override public String process(String item) throws Exception { return item.toUpperCase(); } }) .writer(list -> { list.forEach(item -> System.out.println(item)); }) .build(); } } @Transactional을 걸어도 잘 동작하는데 제가 놓친 부분이있을까요?디버깅을 거며 확인했는데도 잘 모르겠습니다..브랜치는 4.2.4.1입니다.
-
미해결스프링 배치
스키마설정
안녕하세요 강의 초반이지만 대박강의네요 질문이 하나 있습니다배치 설정중에 initialize-schema: never네버라는 설정은 누가 실수로 스키마를 사용할까봐안전 장치용으로 만들어진건가요??(개인적인 생각입니다)
-
미해결스프링 배치
스프링배치와 쿼츠의 연동 질문
안녕하세요, 실무에서 스프링배치를 처음 접하게 되어 알아보던 중 강사님의 강의가 신뢰할 수 있다고 생각되어 신청하였어요. 너무 잘 듣고 있습니다! 다만 강의를 듣다 추가적으로 궁금한 사항이 생겨서 여기저기 찾아보았는데 해결 방법을 찾지 못해 질문을 남깁니다실전예제를 따라하는 과정에서 quartz와 함께 스케줄링을 하는 부분을 보았는데, quartz의 경우 spring batch처럼 메타데이터를 테이블에서 관리할 수 있도록 하는 기능이 있어 해당 설정을 추가하였습니다.spring: quartz: job-store-type: jdbc이렇게 했을 경우 quartz 테이블에 자동으로 JobDetail 및 Trigger 등의 정보가 insert 되어야 할 것 같은데 안 되더라구요, 또한 기존에 작동하던 spring batch의 job이 실행이 되지 않습니다.quartz와 더 관련있는 부분이라 강의 내용과 조금 다른 부분일 거라는 생각에 질문이 조심스러웠지만 해결하고 싶은 마음에 이곳에 글을 남깁니다!
-
미해결스프링 배치
adapter
외부 서비스 호출을 하려면adapter를 사용해야 하는지요?맞다면 청크와 태스크릿 모두 사용이 가능한지와예제 소스 브랜치명 부탁드립니다.
-
미해결스프링 배치
5.0 버전으로 마이그레이션
기존에 하던 프로젝트의 스프링 버전이 3.0.0이라 배치의 버전 또한 5.0을 사용하게 됐습니다. excute 메소드가 실행되지 않는 이유를 알 수 있을까요..??package com.jojoldu.book.freelecspringbootwebservice.config; import lombok.RequiredArgsConstructor; import org.springframework.batch.core.Job; import org.springframework.batch.core.Step; import org.springframework.batch.core.StepContribution; import org.springframework.batch.core.configuration.annotation.EnableBatchProcessing; 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; @Configuration @EnableBatchProcessing @RequiredArgsConstructor 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) { System.out.println("this is step1"); return new StepBuilder("myStep1", jobRepository) .tasklet(new Tasklet() { @Override public RepeatStatus execute(StepContribution contribution, ChunkContext chunkContext) throws Exception { System.out.println("step1 started"); return RepeatStatus.FINISHED; } }, getTransactionManager()) .build(); } @Bean public Step myStep2(JobRepository jobRepository) { System.out.println("this is step2"); return new StepBuilder("myStep2", jobRepository) .tasklet(new Tasklet() { @Override public RepeatStatus execute(StepContribution contribution, ChunkContext chunkContext) throws Exception { System.out.println("step2 started"); return RepeatStatus.FINISHED; } }, getTransactionManager()) .build(); } }
-
미해결[스프링 배치 입문] 예제로 배우는 핵심 Spring Batch
Run / Debug 관련 질문드립니다..!
앞선 질문 보고 다음과 같이 추가를 한 상황인데 Hello World Spring Batch 구문이 실행이 되지 않아 질문을 드립니다..! 혹시 제가 잘못 설정한 부분이 있는 걸까요?
-
미해결스프링 배치
전역변수질문
전역 변수가 리더에서만 리스너 참조하니까 읽히고 프로세서와 라이터에선 안 읽힙니다. 왜 그런걸까요
-
미해결스프링 배치
자료공유 질문
ppt자료는 공유 해도 무방한가요?
-
미해결스프링 배치
Multi-threaded과 Partitioning의 차이가 있나요?
Multi-threaded에다가 각 스레드가 담당할 데이터를 구분시켜주는 기능이 포함된게 Partitioning인가요??단지 차이점이 이렇게만 느껴집니다
-
미해결스프링 배치
AsyncItemReader
AsyncItemReader는 없는 이유가 있나요?읽는거도 비동기처리하면 그만큼 또 메인스레드를 다른용도로 활용할 수 있으니까요
-
미해결스프링 배치
소스코드질문
- 학습 관련 질문을 남겨주세요. 상세히 작성하면 더 좋아요! - 먼저 유사한 질문이 있었는지 검색해보세요. - 서로 예의를 지키며 존중하는 문화를 만들어가요. - 잠깐! 인프런 서비스 운영 관련 문의는 1:1 문의하기를 이용해주세요. 배포해주신 git에 수업하신 모든 코드가 없고 기본 코드만 있는것 같네요 수업의 모든 코드는 어디서 받나요?
-
미해결스프링 배치
멀티스레드 환경에서의 트랜잭션 및 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
-
미해결스프링 배치
43:07 skip 질문입니다.
ItemWriter에서 '12' 아이템이 예외가 터져서 Skip처리 되고, 다시 ItemReader 부터 재실행 되는 것은 이해했습니다.근데 ItemProcessor에서 '6'과 '7' 을 Skip처리한 거처럼ItemWriter역시 마찬가지로 ExecutionContext에 '12' 아이템이 저장되므로 ItemProcessor와 ItemWriter에서 '12' 아이템은 Skip 해야 되지 않나요? 그러면 출력값에 6, -6과 7, -7이 안뜬거 처럼12, -12는 안떠야 된다고 생각합니다.
-
미해결스프링 배치
강의자료 문의드립니다.
안녕하세요. 제가 MAC을 사용해서요.강의자료 PDF로도 혹시 제공 가능한가요. ㅠㅠ 감사합니다.