======================================== [질문 템플릿] 1. 강의 내용과 관련된 질문인가요? (예) 2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (모르겠음) 3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예) [질문 내용] 안녕하세요. 강의를 보다가 궁금증이 생겨서 질문을 올립니다. 강의 도중에 userA,userB를 map에 넣기 위해서, key값으로 String 으로 "userA", "userB"로 입력 하시 는 것을 보았습니다.(사진참조) 근데 어떤 때에는 get으로 값을 넣는 경우도 있는 것을 생각 할수 있었 습니다. (추가1: getName으로 넣어도 되는거 아닌가?라는 생각 때문에 다른 강의들에서 레파지토리는 어떻게 했는지 살펴봄) (예전 강의에서 save할때) 그래서 어떤 것이, 더 나은 선택 인지, 저는 모르겠습니다. 그래서 어떤 때에는 get으로 값을 써야 하고, 어떤 때에는 직접 타자로 값을 쳐서 입력해야 하는지 알고 싶습니다. 답변 부탁 드립니다.
가령 다음과 같이 g etExecutionContextSerializer() 메서드를 오버라이드하면 g에 볼드처리안됨 -- 원시적 침투 예제의 BatchConfig에서 DefaultBatchConfiguration 상속을 제거하고@EnableBatchProcessing을 추가하자. 다음과 같이 말이다. 예제 밑의 예제가 그냥 기존 DefaultBatchConfiguration 방식만 나와있음 아마 기존과 수정을 두개 다 표시하는식으로 하고싶었을거같음 -- JobContext/StepContext: Late-Binding의 최종 무기고 키룩형 JobContext/StepContext가 존재하면 배치 스코프가 활성화된 상태라는 것은 알겠어. 근데 이 JobContext/StepSontext 대체 어디에 써먹는거지? 단순히 활성화를 의미하는게전부인가? 키룩형 -> 갈매기가 되고싶은 내면의 소리일수있음 괜찮음 주변에 돌멩이 지망생도 있고 독수리 지망생,딸기우유 지망생도 있어서 이해할수있음
좋은 추석 보내고 계신가요? 현재 코틀린으로 강의를 따라해 보고 있습니다. class Member private constructor( val email: String, var nickname: String, var passwordHash: String, var status: MemberStatus, ) { fun activate() { check(status == MemberStatus.PENDING) { "회원이 PENDING 상태가 아닙니다" } this.status = MemberStatus.ACTIVATE } fun deactivate() { check(status == MemberStatus.ACTIVATE) { "회원이 ACTIVE 상태가 아닙니다" } this.status = MemberStatus.DEACTIVATED } fun verifyPassword( password: String, passwordEncoder: PasswordEncoder, ): Boolean = passwordEncoder.matches(password, this.passwordHash) fun changeNickname(nickname: String) { this.nickname = nickname } fun changePassword(password: String) { this.passwordHash = password } companion object { fun create( email: String, nickname: String, password: String, passwordEncoder: PasswordEncoder, ): Member = Member( email, nickname, passwordEncoder.encode(password), MemberStatus.PENDING, ) } } 이러한 식으로 작성하였는데 자바에서는 const로 선언한 객체나 변수가 아닌 이상 기본적으로 가변입니다. 그런데 코틀린에서는 val, var 키워드에 따라서 var로 선언해야 가변 타입이 됩니다. Member 도메인 모델 확장 챕터 수강하고 있는데 이 경우는 도메인에서 가변 속성을 미리 정의하고 해당 속성들을 var로 선언하는 것이 맞을지, 혹은 val을 통해 불변성을 확보하고 새 객체를 생성하여 변경을 처리하는 것이 적합할지 궁금합니다. 코틀린에서 도메인 코드를 작성할 때 자바와 다른 문법&개념과 도메인 중심 설계가 종종 난해할 때가 있네요.
학습하는 분들께 도움이 되고, 더 좋은 답변을 드릴 수 있도록 질문전에 다음을 꼭 확인해주세요. 1. 강의 내용과 관련된 질문을 남겨주세요. 2. 인프런의 질문 게시판과 자주 하는 질문(링크)을 먼저 확인해주세요. (자주 하는 질문 링크: https://bit.ly/3fX6ygx) 3. 질문 잘하기 메뉴얼(링크)을 먼저 읽어주세요. (질문 잘하기 메뉴얼 링크: https://bit.ly/2UfeqCG) 질문 시에는 위 내용은 삭제하고 다음 내용을 남겨주세요. ========================================= [질문 템플릿] 1. 강의 내용과 관련된 질문인가요? (예) 2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (아니오) 3. 질문 잘하기 메뉴얼을 읽어보셨나요? (아니오) [질문 내용] 여기에 질문 내용을 남겨주세요. 자바부터 강의를 듣고있는데 언어가 이해가 되는부분이 있고 안되는 부분이있는데 이거는 앞에가서 다시 학습을 하고와야하나요!? 지금 스프링입문은 여기서 다이해하고 다음 강의로 넘어가야 하는 건가요!?
SimpleStepHandler - Step 실행의 관리자 Step의 실행은 StepHandler에 의해 의해 통제된다. Spring Batch는 기본 구현체로 SimpleStepHandler를 사용하는데, 이 컴포넌트가 Step 실행의 전체 라이프사이클을 관리한다. 의해 의해 <- 그리고 Step Squad 핵심 요약 있으니까 너무좋은데 Job Squad 에서도 핵심요약이 있었으면 더 좋았을거같음 뭐 스탭이나 잡이나 내용이 거의 비슷비슷하긴한데(Execution 반드시 새거만들고,상태변경시 즉시 메타데이터저장소에 저장하고) 그래도 실제 실행 따라가는 느낌이라 정리가 잘 안되는느낌이긴해서 마지막에 방점찍으면 보기 더 편할거같은느낌
안녕하세요. 우선 한푼도 아깝지 않은 명강의를 만들어주심에 진심으로 감사드립니다. WebApiExRateProvider를 템플릿 콜백 패턴을 적용한 구조로 변경하면서, 토비님께서는 실제 API를 호출하고 콘솔에 찍힌 결과를 보며 진행한 테스트 방식에 의문이 들어 한번 테스트 코드를 만들어보았는데요. 피드백을 받아보고 싶습니다. 코드는 GitHub Repository에 Commit 내역에서 확인하실 수 있습니다. ( Commit 내역 링크 ) 의도에 대해 간단히 설명드리면 반드시 지정된 URL로 API 호출을 보내야 한다는 동작 과 특정 스펙의 JSON을 파싱해서 환율 정보를 반환하는 동작 을 테스트했습니다. 이때 ApiExecutor 의 경우 단순히 API를 호출하고 그 응답을 반환하는 역할이므로 테스트 할 가치가 없다고 판단하여 배제 했습니다. 주로 궁금한 것은 다음과 같습니다. 테스트하려는 기능에 대해 부족하거나 과함은 없는지? Mock을 활용한 테스트 방식에 대해서는 아쉬움이 없는지? 아무래도 Mock을 활용한 테스트에는 찝찝함이 남아있는데, 어떻게 해소할 수 있을지? 토비님이라면 어떤 식으로 테스트를 진행하셨을 지? 다시 한번 좋은 강의 제공해주셔서 진심으로 감사합니다.
Non-repeatable read가 발생 가능한 Read Committed 격리 수준에서 어떻게 비즈니스 로직의 정합성을 유지할 수 있는지 바로 이해하지 못했다가, 검색 및 추론을 통하여 아래 [1]과 같이 이해했습니다. 질문 제가 잘 이해했는지 확인하기 위해서 질문드렸습니다! 혹시 근본적으로 오해한 부분이 있을까 두렵습니다ㅠㅠ 제가 잘 이해한 것이 맞다면, Read Committed 격리 수준을 사용할 때 데이터 정합성을 유지하기 위한 디테일들을 신경쓰면서 데이터 접근 계층의 로직을 작성하는지 궁금합니다. [1] 제가 이해한 Read Committed 격리 수준에서 데이터 정합성을 유지하기 위한 가정 및 필요조건 JPA를 사용한다. RDBMS가 Read Committed 격리 수준을 구현할 때 MVCC를 사용한다. 이유: JPA를 활용하여 비즈니스 로직을 작성할 때 데이터베이스 전역적으로 잘 정의된 일관적인 스냅샷이 존재한다고 가정하기 때문 JPA로 작성한 코드가 항상 JPA의 1차 캐시를 cache hit하는 경우 Repeatable Read 격리 수준처럼 사용해도 무방하다. JPA에서 Lazy Loading을 사용한다면, 다른 MVCC 스냅샷의 데이터가 조회될 때에도 비즈니스 로직의 정합성이 깨지지 않는 맥락에서만 사용한다.
반말은 조금 부끄러워서.. 존댓말로 질문드리겠습니다. ItemWriter에서 예외 발생 시 재시도 - 청크 단위로 재시도 관리 1. ItemWriter에서 예외 발생 시 ItemProcessor부터 처리가 재개된다. 2. ItemProcessor에서와 달리, ItemWriter에서의 재시도 횟수는 청크 단위로 관리된다. 요 부분에서 실제로 배치를 돌려보니 writer부터 재시작하는 것을 확인 가능했습니다.. 관련해서 원인을 분석해보니, 아래 결론에 도달했는데 맞을까요? processorNonTransactional() 설정이 켜져있으면 Item 단위로 처리 결과를 캐시에 저장하기때문에 processor는 모두 완료 처리 -> writer부터 시작 processorNonTransactional() 설정이 꺼져있으면 청크 단위로 완료 처리하기때문에 processor부터 다시 시작
킬구형, 청크 지향 처리 시 벌크 read를 할 수 있는 방법이 있어? ItemReader 사용 시 소스에서 1건 씩 데이터를 읽어온다면, 단건 SELECT문이 매번 날아가거나 아니면 JDBC의 ResultSet next()를 사용하는 것 같은데,, 전자면 DB 부하가 너무 심하고 후자여도 네트워크 IO가 꽤 발생할 것 같은데.. 지금 수백? 수천만? 건 정도의 데이터를 마이그레이션 해야하는 업무를 받았는데, 청크 생성 시 DB 부하나 네트워크 트래픽을 좀 줄이고 싶은데 다건 SELECT를 통해 처리하는 방법이 있을까?
마지막 강의에서 진행한 헥사고날 아키텍처 테스트에서 저는 아래와 같이 에러가 발생하고 있는데 어떻게 수정을 해야 할까요? 소스 코드는 동일한 것 같은데... 무엇이 차이인지 모르겠어요 13:09:39.840 [Test worker] INFO com.tngtech.archunit.core.PluginLoader -- Detected Java version 17.0.12 Architecture Violation [Priority: MEDIUM] - Rule 'Layered architecture considering all dependencies, consisting of layer 'domain' ('com.inflearn.splearn.domain..') layer 'application' ('com.inflearn.splearn.application..') layer 'adapter' ('com.inflearn.splearn.adapter..') where layer 'domain' may only be accessed by layers ['application', 'adapter'] where layer 'application' may only be accessed by layers ['adapter'] where layer 'adapter' may not be accessed by any layer' was violated (1 times): Method <com.inflearn.splearn.SplearnTestConfiguration.passwordEncoder()> calls method <com.inflearn.splearn.domain.member.MemberFixture.createPasswordEncoder()> in (SplearnTestConfiguration.java:19) java.lang.AssertionError: Architecture Violation [Priority: MEDIUM] - Rule 'Layered architecture considering all dependencies, consisting of layer 'domain' ('com.inflearn.splearn.domain..') layer 'application' ('com.inflearn.splearn.application..') layer 'adapter' ('com.inflearn.splearn.adapter..') where layer 'domain' may only be accessed by layers ['application', 'adapter'] where layer 'application' may only be accessed by layers ['adapter'] where layer 'adapter' may not be accessed by any layer' was violated (1 times): Method <com.inflearn.splearn.SplearnTestConfiguration.passwordEncoder()> calls method <com.inflearn.splearn.domain.member.MemberFixture.createPasswordEncoder()> in (SplearnTestConfiguration.java:19) at com.tngtech.archunit.lang.ArchRule$Assertions.assertNoViolation(ArchRule.java:94) at com.tngtech.archunit.lang.ArchRule$Assertions.check(ArchRule.java:86) at com.tngtech.archunit.library.Architectures$LayeredArchitecture.check(Architectures.java:347) at com.inflearn.splearn.HexagonalArchitectureTest.hexagonalArchitecture(HexagonalArchitectureTest.java:22) at java.base/java.lang.reflect.Method.invoke(Method.java:569) at com.tngtech.archunit.junit.internal.ReflectionUtils.invoke(ReflectionUtils.java:111) at com.tngtech.archunit.junit.internal.ReflectionUtils.invokeMethod(ReflectionUtils.java:103) at com.tngtech.archunit.junit.internal.ArchUnitTestDescriptor$ArchUnitMethodDescriptor.execute(ArchUnitTestDescriptor.java:203) at com.tngtech.archunit.junit.internal.ArchUnitTestDescriptor$ArchUnitMethodDescriptor.execute(ArchUnitTestDescriptor.java:173) at java.base/java.util.ArrayList.forEach(ArrayList.java:1511) at java.base/java.util.ArrayList.forEach(ArrayList.java:1511)
안녕하세요 !! 도메인 모델의 값 객체 도입편에서 궁금한게 있습니다. 패스워드는 passwordEncoder를 의존하여 암호화와 매치 여부를 확인합니다. 이메일 vo는 검증 패턴이 member만 사용하는 것이 아니라 다른 곳에서도 사용할 수 있고 중복된 코드를 줄이기 위해서 변경하셨습니다. password도 이메일 vo처럼 매번 passwordEncoder를 주입받는 게 아니라 password VO를 만들어서 관리할 수 있을거같은데 패스워드는 의존성 주입으로 해결하게 되신 이유가 궁금합니다
오타 발견 root@4ea86c29f1f7:/data# redis-cli set attack:2 "{\"id\":2,\"timestamp\":\"${TODAY}T09:28:47\",\"targetIp\":\"203.0.113.50\",\"attackType\":\"XSS\",\"payload\":\"<script>alert('HACKED!');</script>\"}" 위 명령어 실행 시, 아래와 같은 에러 메시지 발생! bash: !': event not found 에러 발생 원인 bash: !': event not found 에러는 Bash의 히스토리 확장(history expansion) 때문에 납니다. ! 문자(예: HACKED! )가 들어가면 bash가 ! 로 시작하는 히스토리 토큰(예: !! , !$ , !123 )으로 해석하려 하고, 매칭되는 히스토리 항목이 없으면 event not found 오류가 납니다. set +H # 히스토리 확장 끄기 ... redis-cli set attack:2 "{\"id\":2,\"timestamp\":\"${TODAY}T09:28:47\",\"targetIp\":\"203.0.113.50\",\"attackType\":\"XSS\",\"payload\":\"<script>alert('HACKED!');</script>\"}" ... set -H # # 히스토리 확장 켜기 OK redis key들을 set 하기 전에 히스토리 확장을 끄고 실행할 경우 정상 동작
3. 웹개발 코스 [Enterprise Architecture(EA) X 전자정부프레임워크]
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'sampleService': Injection of resource dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'sampleDAO': Injection of resource dependencies failed; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'sqlMapClient' available Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'sampleDAO': Injection of resource dependencies failed; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'sqlMapClient' available Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'sqlMapClient' available --실행하면 404에러 뜹니다.
강의 예제를 따라가면서 SystemFailureJobConfig 배치를 실행했는데, 계속 FlatFileItemReader에서 JobParameter로 전달한 inputFile이 null로 들어오는 문제가 발생했다. 정확하게는 Caused by: org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.springframework.batch.item.file.FlatFileItemReader]: Factory method 'systemFailureItemReader' threw exception with message: Path must not be null 이 오류 였으며, public FlatFileItemReader<SystemFailure> systemFailureItemReader( @Value("#{jobParameters['inputFile']}") String inputFile) { log.info("오잉 Reader inputFile: " + inputFile); // null return new FlatFileItemReaderBuilder<SystemFailure>() .name("systemFailureItemReader") //여기서 path not null 오류 발생 .resource(new FileSystemResource(inputFile)) .delimited() .delimiter(",") .names("errorId", "errorDateTime", "severity", "processId", "errorMessage") .targetType(SystemFailure.class) .linesToSkip(1) .build(); } .name("systemFailureItemReader") 이 위치에서 발생하고 있었다. 그리고 line numbers are likely diverged. try to find the current location inside 'SystemFailureJobConfig. systemFaliureItemReader()' 이 메시지도 함께 보였다. GPT에 물어봐서 해결이 되긴 했는데, KillBatchSystemApplication에서 CommandLineRunner를 구현하고 직접 경로를 지정해주었다. @SpringBootApplication @AllArgsConstructor public class KillBatchSystemApplication implements CommandLineRunner { private final JobLauncher jobLauncher; private final Job systemFailureJob; public static void main(String[] args) { SpringApplication.run(KillBatchSystemApplication.class, args); } @Override public void run(String... args) throws Exception { JobParameters params = new JobParametersBuilder() .addString("inputFile", "/Users//Desktop/kill-batch-system2/system-failures.csv") .toJobParameters(); jobLauncher.run(systemFailureJob, params); } } 실무에서는 CLI로 파라미터를 전달하는것이 핵심이라 했던걸로 기억한다. CLI로 전달한 JobParameter를 StepScope Bean에서 안전하게 받는 다른 방법은 없나?? 아 지금 작업도구는 MacOS M1, Spring Boot 3.4.7 이다. 연휴 잘 보내길 바란다.
청크 단위로 트랜잭션 된다는건 이해했다. 그에 관련해서 궁금증이 생겼는데, reader, processor에서 처리하다가 Exception이 나도 사실 DB엔 롤백할게 없으니 사실상 Writer 작업 중에만 단 한번 롤백이 수행될 것이라고 예상되는데 맞는가? read 시에, process 도중에도 롤백이 일어날 경우가 있는지 궁금하다. 추가로 과거 스프링 배치 공식 문서의 잘못된 다이어그램 이라던지 null을 줘야 끝난다는 점과 97개 와 같이 자세한 예시를 들어준 점, read(), process()가 각각 10번씩 수행된다는 것과 같이 사용자들이 많이 헷갈려 하는걸 명확하게 알려줘서 좋은 것 같다.
앞선 질문에 대한 답변 고맙다 미스터 KILL-9 덕분에 손쉽게 엑셀을 처형 (처리)할 수 있었지 하지만 그 다음 관문이 존재하는군 후후.. 각 STEP 마다 RepeatStatus 에 따라서 트랜잭션이 보장하는건 이해했다 하지만 여러 관계가 존재하는 테이블 데이터 적재 시 트랜잭션을 어떻게 보장할지 감이 안온다 미스터 KILL-9 예를 들어 설명하지.. FILE-A, FILE-B 각각 다른 컬럼을 가진 파일들이지 FILE-A는 TABLE-A에 적재하고 FILE-B는 TABLE-B에 적재한다 각 FILE 당 ROW 100개씩 읽으면서 적재하고 문제가 생기면 해당 100건만 롤백할텐데 문제는 TABLE-A 와 TABLE-B의 관계다 TABLE-A 가 부모고 TABLE-B자 자식 테이블인 상황에서 특정 TABLE-B 데이터 롤백 시 TABLE-A 데이터도 마찬가지로 롤백 해야할거 같은데 이런 경우 어떻게 원자성을 보장할 수 있는가에 답변할 수 있겠는가..? 현재 내가 떠오른 방안은 결국은 모든 데이터 처리이니 특정 부분 처리 실패하면 데드 DLQ (Dead Letter Queue) 에 담아서 나중에 처형( 처리)하도록 해야하나 싶다!
Spring Boot + Kotlin + java 21로 진행중이다. 먼저 좋은 강의 너무 고맙고, 나도 다른 사람의 Q&A 처럼 BatchConfig가 있어서 수행시에 부트만 떴다가 꺼지고 아무것도 출력되지 않아서 당황했다 (그래서 강의 자료에 더이상 불필요하다 보다는 제거하라고 명시하면 좋을 것 같다) 질문이 있는데 1. BatchConfig가 있고 없고가 어떤 것 때문에 수행결과에 차이점을 주는거야? 2. Kotlin을 사용한 Spring Boot에서는 @Import를 사용하지 않았는데, 이때도 자동으로 설정을 해주는걸까? BatchConfig가 있다는 것 자체로 배치 수행은 안하고 부트가 바로 끝나버려 두 질문 다 그냥 궁금증일 뿐이다. BatchConfig를 제거하면 수행에는 문제가 없다.