전체 글(109)
-
Spring AOP의 자기 호출(Self-Invocation) 이슈
self-invocation이란self-invocation은 한 객체 안에서 자기 자신의 다른 메서드를 호출하는 걸 의미합니다.평범한 자바코드에서는 아무 문제 없지만 Spring AOP 기반 기능(@Transactional, @Async, @Cacheable 등)을 쓸 때 내부에서 호출한 메서드에는 어노테이션이 동작하지 않기 때문에 문제가 발생합니다. @Servicepublic class UserService { private final UserRepository userRepository; public UserService(UserRepository userRepository) { this.userRepository = userRepository; } publi..
2026.09.10 -
@Async로 UX 개선하기
문제 상황이 글에서 데이터를 저장한 뒤, Gemini API로 분석하는 기능을 이벤트 기반으로 처리했습니다.이제 문제는 분석에 최소 1분의 시간이 걸린다는 것입니다. 사용자는 데이터 등록 버튼을 누르고 화면이 멈춘 채로 1분 이상의 시간을 기다려야 합니다. 로직상 에러는 없지만 사용자 입장에서 지금 로딩화면이 정상적으로 등록 중이라 멈춘 건지 아니면 무언가 에러가 발생해서 멈춘건지 알 수 없기 때문에 UX관점에서 보면 정말 좋지 않다고 할 수 있습니다. 생각해 보면 사용자가 이 시간을 기다릴 필요는 없습니다.데이터 등록 자체는 순식간에 끝나는 동작이고, 뒤이은 분석은 사용자의 입력이 끝났으니 별개의 작업으로 돌릴 수 있습니다.그래서 데이터 저장 작업이 끝나면 바로 사용자에게 응답하고 데이터 분석 작업은 ..
2026.09.09 -
Service Interface를 반드시 생성해야 하는가
서비스 레이어 클래스를 만들 때 항상 interface를 만들고 그 구현체를 만드는 방식으로 클래스를 추가했습니다.처음 스프링을 배울 때 그렇게 배워서 계속 관습적으로 사용하고 있었는데 항상 메서드를 추가할 때마다 파일 2개에 모두 추가해야 한다는사소한 귀찮음에서 하나 의문이 생겼습니다. interface를 필요한 클래스에만 쓰면 훨씬 프로젝트 관리도 쉬워지고 코드도 깔끔해질 것 같은데, 왜 구현체가 하나밖에 없는데도 꼭 interface를 만들까? 그래서 이번 기회에 한 번 알아봐야겠다라 생각했습니다. interface를 생성하는 게 왜 관습적으로 고착되었는가이에 대해서 알아보기 위해서는 스프링에서 프록시 객체를 만드는 방법에 대해 알아야 합니다. 우선 프록시 객체에 대해서 간단하게 설명하면 "대..
2026.09.07 -
트랜잭션 전파 레벨(REQUIRES_NEW)의 함정과 이벤트 기반 해결
문제 상황요구 사항데이터를 저장한 뒤, 해당 데이터를 DB에서 불러와 Gemini API로 분석하는 기능을 구현하려 했습니다.필수적인 요구 사항은 Gemini API를 통한 데이터 분석은 매일 스케쥴러를 통해 이뤄지고 있고, 중요한 데이터가 아닌 부가적인 데이터이므로 분석이 실패하더라도, 앞서 저장한 데이터(분석 대상)는 안전하게 DB에 저장되어야 했습니다. 그래서 Gemini 분석 메서드만 따로 분리해 트랜잭션 전파 방식을 REQUIRES_NEW로 부여해서 Gemini 분석이 실패해 롤백되어도 원래 트랜잭션까지 롤백되지 않게 하려 했습니다. 발생한 에러/문제REQUIRES_NEW 메서드 내부에서 방금 저장한 데이터의 ID로 호출했으나, 데이터를 찾지 못하는 문제가 발생했습니다. 원인 분석REQUIR..
2026.08.13 -
백준 11004
문제 문제 접근N의 최댓값이 5,000,000이므로 O(NlogN)의 복잡도로 풀면된다.퀵 셀렉트의 경우 최악의 경우 시간복잡도가 O(N^2)이지만, 공부를 위해 이번에는 퀵 셀렉트 사용해서 문제를 풀어보기로 하였다.퀵 셀렉트는 퀵 정렬에서 한쪽만 골라 재귀하는 방법을 말한다. 매 정렬마다 pivot을 K와 비교하는데,pivot == K: K번째 수를 찾았으므로 알고리즘 종료pivot > K: pivot의 왼쪽부분에 K가 있으므로 왼쪽만 정렬 수행pivot : pivot의 오른쪽부분에 K가 있으므로 왼쪽만 정렬 수행위와 같은 조건으로 선택해서 정렬과정을 진행하면 된다. 코드 public static void main(String[] args) throws IOException { Buf..
2026.08.05 -
백준 11399
문제 문제 접근문제에서 나와있듯이 가장 짧은 시간이 걸리도록 순서를 세우고 그 값을 구해서 출력하면 된다.앞에 서있는 사람이 인출하는 데 걸리는 시간만큼 뒷사람의 인출시간도 늘어난다고 생각하면, 인출시간이 짧은 사람을 순서대로 앞에 세우면 최단시간이 걸린다는 걸 쉽게 알 수 있다. N의 최댓값이 1000이고 시간제한이 1초이므로 시간복잡도가 $O(N^2)$인 정렬 알고리즘 중 아무거나 사용해도 되므로, 이번 문제에서는 삽입 정렬을 이용해서 문제를 풀어보았다. 문제 풀이 public static void main(String[] args) throws IOException { BufferedReader br = new BufferedReader(new InputStreamReader(Sy..
2026.08.04