[Test] DataSource Bean & properties(yaml) & SQLGrammarException: could not prepare statement [Table ~~ not found]
·
JAVA/Application
■ 단일 DataSource 설정properties/yaml에서 db connection 설정 방법은 이렇다.spring.datasource.properties.driverClassName=...spring.datasource.url=...spring.datasource.username=...spring.datasource.password=... 하지만 만약 멀티 데이터소스 요구사항이 다른 경우, 위와 같은 properties에 따른 기본적인 DataSource가 필요한 것이 아니라, 별도로 구현해둔 빈이 필요할 수 있다. (🔗 예를 들면 이런 상황) 그리고 그런 커스텀 DataSource를 사용하도록 테스트 환경을 구성할 때 어떻게 DataSource와 DB 접속 정보를 설정해야 하는지, 놓칠 수 있..
Springboot 3 Migration (from 2.6)
·
미분류글
■ Introspringboot 3으로 마이그레이션한 과정과, 내 프로젝트에서 해결한 문제를 기록한다. 일반적으로 springboot 3 마이그레이션시 만나는 문제를 다양하게 만날 수 있어서 좋았다.  보안과 유지보수 측면에서 마이그레이션을 해야 한다. 마이그레이션 대상 프로젝트는 2.6.x를 사용중이었고 이걸 스부 3 이상으로 마이그레이션 하는 것이 목표다. 마이그레이션 순서를 간략히 정리하면, 자바 17로 버전업 후 springboot 2.7로 중간 버전업 해서 종속성 문제 해결 뒤 springboot 3.x으로 버전업해서 나머지 종속성을 해결하는 것이다. 2.7로 중간 버전업하는 거는 springboot 버전이 낮은 편이었다거나 하면 도움이 될 것이다. 참고로 나는 2.6을 쓰고 있었는데 2.7로 ..
MDC를 사용해 멀티쓰레드 로깅하기 (for 쓰레드간 Context 전달)
·
JAVA/Application
■ Intro멀티쓰레드 환경의 비동기 로깅을 해야했고, MDC를 활용했다.상황을 설명하자면 요청 경로는 동일하게 들어오지만 중간에 쓰레드가 나뉘는 코드가 있었는데, 요청의 컨텍스트를 유지하고 있어야 했다. 예를들어 처리시간을 로깅하려면 처리시작 시간을 보유하고 있어야 어디선가 처리가 끝날 때 총 처리 시간을 구할 수 있다. 비동기일 경우 처리가 끝나는 시점을 모르기 때문에, 그런 최적의 방법에 대한 고민이 필요했다. 결론적으로 MDC + TaskDecorator + AOP를 통해서 구현했다. 비동기 처리의 완료시점을 확실히 하는 것이 중요하므로 MDC를 사용하여 쓰레드를 트래킹하는 것이 적절해보였다. TaskDecorator가 MDC 컨텍스트를 분기 대상 쓰레드로 넘겨서 종료시점까지 정보를 유지하려는 방..
[Springboot] 스케줄러 동적 등록/삭제/변경
·
JAVA/Application
■ Intro동적으로 스케줄링 정보를 변경해야 할 일이 있다. 예시로 스케줄링 주기를 중간에 바꿔야 한다든가, 스케줄 내용을 변경해야 한다든가 말이다. 값이 동적으로 들어오는 위치를 DB라면, DB의 데이터 변경을 자동으로 알아차린 후 스케줄러를 변경시켜야 한다. 그래서 지난 번에는 어떻게 변경감지를 할지 고민했었고, 폴링으로 감지하기로 결정했다. 이번에는 데이터 변경이 감지된 후 스케줄러를 동적으로 변경하는 방법을 정리하겠다. ■ 샘플 구조예시로, 1분마다 DB에서 '주기 값'이 변경되었는지 확인하고, 스케줄러에 반영하는 간단한 샘플 구조를 작성했다. 각자의 비스니스에 맞게 커스텀해서 사용하면 될 것이다. @Componentpublic class SampleDynamicScheduler {    pri..
DB 데이터 변경 감지 방법 | 폴링 or 이벤트
·
Database
■ IntroDB 데이터 변경을 감지해야할 일이 있다. 서버의 어떤 동작이 외부 설정데이터에 영향을 받기 때문에 변경을 감지해서 동작을 수정해야 하는 상황이다. 그래서 일반적인 방법들을 정리해보고자 한다. (참고: 프론트엔드 부분은 제외하고 이야기한다.) 먼저 확인보자면 여기에서는 "실시간 데이터 처리와 변경 감지는 많은 비즈니스 애플리케이션에서 중요한 요구 사항으로 자리잡고 있습니다. 데이터베이스에서 특정 테이블이나 데이터를 감시하는 방법은 다양하지만, 전통적으로 트리거를 활용한 방식이 가장 많이 사용되었습니다." 라고 말한다. (그래서 뭘 해야하는데? 이 글에서 알아볼 것이다.) 앞으로도 데이터 변경 감지를 적절한 방법으로 해내기 위해서, 다양한 변경 감지 방법들을 알고 있도록 하자. 변경 감지는 두..
[Spring] DTO 매핑시 특정 키만 null 값
·
JAVA/Application
나머지 값들은 다 정상적으로 매핑되어 값이 잘 들어가는데, 특정 키만 null로 들어가는 것을 발견했다.원인은 필드명이었다. 아래 글 덕분에 알게 되었다. https://bcp0109.tistory.com/309 Spring Request DTO 에 null 값이 들어가는 이유 (Jackson, Lombok)Overview Spring Boot 로 REST API 를 테스트 하다가 이상한 이슈에 직면했습니다. 클라이언트에서 @RequestBody 로 요청을 받기 위한 DTO 클래스를 만들고 값을 입력 받았는데 null 값이 입력되는 겁니다. 처bcp0109.tistory.com  문제가 되는 필드명은 cId였다. 소문자 하나 다음에 바로 대문자가 나오는 필드명이 문제가 되는 것이다. Spring은 htt..
[Spring AOP] Consumer onMessage() 비동기 수신 로깅
·
JAVA/Application
■ AOP를 통해 onMessage() 비동기 수신 로깅 Redis가 Consume할 때 호출되어 작업을 처리하기 시작하는 부분인 onMessage() 메서드를 AOP를 통해 로깅하려는 상황이었다. 기능 구현을 위한 샘플 코드를 짜서 테스트해보았다. 구조는 이러하다.- ConsumerFactory: 메시지를 구독할 컨슈머들을 생성- StreamListenerImpl: 구독한 메세지를 처리할 onMessage 구현- ListenContainer: 위 리스너를 관리할 컨테이너 설정- LoggingAspect: 테스트 대상인 Aspect들- RedisConfig: 기본 레디스 설정  *참고: ListenerContainer, Listener, 그리고 Consumer 객체간의 관계를 이해하는 것이 필요하다면, ..
[Redis] cannot deserialize from Object value (SerializationException)
·
JAVA/Application
Springboot Cache를 적용하고자 할 때 발생가능한 오류입니다.- 저는 redis cache 사용했습니다.- 또한 캐시 value에 대해서 GenericJackson2JsonRedisSerializer를 적용했습니다. 서버에 캐시를 적용했는데 만약 이런 에러를 만났다면, jackson의 역직렬화에 대해 생각해봅시다.캐시된 응답을 올바른 객체로 내보내야 하는데 역직렬화할때 쓸 생성자가 없다면cannot deserialize from Object value를 로그에서 만날 수 있습니다.*생성자의 존재 문제가 아닌, 역직렬화하기 적절한 생성자를 두는 것이 핵심입니다.org.springframework.data.redis.serializer.SerializationException: Could not ..
다량의 이미지 업로드 속도 최적화 / 트래픽 대비 / 비동기 처리
·
JAVA/Application
■ 리뷰등록시 문제 가능성너무나도 희망찬 이야기겠지만,만약 우리 서비스의 인기가 폭발해서동시에 많은 유저가 사진리뷰를 업로드한다면 어떨까? 동기적으로 처리할경우 대용량 사진 업로딩이 하나라도 있다면, 뒤를 이을 수많은 업로딩이 블로킹되며 작업이 주르륵 지연된다. 그래서 이때는 비동기 처리를 생각해야 한다.  이 상황을 대비하고자 하여..문제의 코드를 수선해봤다.  ■ 성능 측정 (TPS)2초 안에 25건의 스레드(사용자)를 실행함 (= 약 0.08초마다 스레드를 순차 실행)각 스레드(사용자)는 요청을 총 4개 보냄(= 총 100건의 요청을 보내는 테스트) □ 변경 이전  □ 변경 이후전반적으로 TPS도 상승하고,처리시간도 약 0.65배로 단축했다.  "> □ 비동기 + Multipart 관련 문제 해결사..
[Redis] StreamListener(onMessage)와 Consumer 객체간 관계
·
미분류글
□ IntroSpringboot와 Redis를 통하여 메시지 비동기 처리를 할 때 StreamListener와 Consumer를 만나게 된다. 내가 원하는 구독자시스템, Pub/Sub, 메시지 처리 구조를 만들기 위해서는 StreamListenerContainer와 StreamListener, 그리고 Consumer 객체 사이의 관계를 이해하는 것이 필요하다.□ StreamListener와 Consumer의 관계 이해하기 StreamListener와 Consumer는 1:1로 연결을 맺고 있는 구조다.StreamListener와 Consumer가 관계지어지면 Subscription 객체를 생성한다. 아래 구조는,각 Consumer가 서로 다른 StreamListener와 맺어져 있고,이에 따라 서로 다른..