회사에서 FastAPI + SQLModel 기반 프로젝트를 하고 있어 SQLModel을 공부했습니다. 공식문서 번역본에 가깝지만 나름대로 이해한 내용을 정리해봤습니다. 이 글은 sqlalchemy 2.0.4 버전을 기준으로 작성했습니다. SQLModel은 SQLAlchemy를 기반으로 동작하므로, 데이터베이스 연결은 create_engine에서 생성된 Engine 객체가 관리합니다.Engin은 커넥션 풀과 Dialect를 통해 애플리케이션에 전달되는 데이터베이스의 시작점입니다.DBAPI란?Python Database API Specification의 약자로, 모든 데이터베이스 커넥션 패키지에 대한 일반적인 사용 패턴을 정의하기 위해 파이썬의 PEP 249에 정의된 스펙입니다. DBAPI는 파이썬 애플리케..
MEETPLUS 프로젝트 당시 프론트에서 HTTP GET 요청을 했는데 CORS 오류가 발생했습니다. 클라이언트 모든 요청은 gateway를 통해 들어오고 있었고, Spring Cloud Gateway 서버가 gateway 역할을 담당하고 있었습니다.gateway에서는 MSA의 각 도메인 서버별로 구체적인 경로와 필터를 지정해 준 상태였습니다.그런데 왜 CORS 오류가 발생했을까요? 이는 preflight 요청때문이었습니다.preflight 요청이란, 브라우저가 서버에 요청을 보내기 전에 이 요청을 허용할지를 확인하기 위해 보내는 예비 요청입니다.preflight 요청이 발생하는 조건1. CORS 요청이 "단순 요청(Simple Request)" 조건을 충족하지 않는 경우단순 요청의 조건은 다음과 같습니..
spring boot 애플리케이션 환경설정을 Spring Cloud Config로 관리하고 있었습니다.환경설정 파일(ex. application.yml)은 github private repository에 저장하고 Spring Cloud Config가 애플리케이션 실행 시 맞는 환경설정 파일을 가져와 적용해줍니다. 그런데 환경설정을 수정할때마다 변경사항을 적용하기 위해 /actuator/refresh API 를 호출해야했습니다.이는 환경설정이 빈번하게 수정되는 개발기간에 상당히 귀찮았고, 게다가 MSA에서 여러 애플리케이션들의 auctuator API를 호출하는 것도 비효율적이었습니다. 요구사항은 다음과 같았습니다.1. 레포지토리에 push하면 자동으로 수정된 환경설정이 적용될 것2. 한번의 동작으로 여러..
*긴글 주의*AWS ECR을 사용하게된 계기이때까지 github action에서 docker hub로 docker image를 push/pull해왔습니다.그러다가 pull에서 더이상 진행되지 않는 현상이 종종있었습니다.아무래도 무료계정을 이용하다보니 월 200회 pull 제한에 걸려서 그런 것 같습니다.현재 진행하고 있는 프로젝트는 배포가 빈번히 일어날 것이기 때문에 docker hub를 사용하기에 부적합했습니다.그리고 public 레포지토리에 이미지를 올려놔서 보안상 문제가 있었습니다. 장점 및 단점그래서 대안을 찾아보던 중, AWS에서 완전 관리형 컨테이너 레지스트리인 ECR (Elastic Container Registry)을 사용해서 CI/CD를 구축하는 방법을 알게되었습니다. 일단 장점은1. 컨..
jdbc로 다중 데이터베이스를 설정하여 JPA에서 사용하는 방법을 소개합니다.spring boot 3.0부터는 @EnableBatchProcessing을 권장하지 않습니다. 이걸 쓰면 자동으로 등록해주던 빈들을 수동으로 설정해야합니다.이 글에서는 @EnableBatchProcessing를 사용하지 않습니다.이말고도 다른 방법이 얼마든지 있으니 참고만 해주시기 바랍니다.IDEA: intellij사용한 데이터베이스: postgreSQLspring batch 5.0.5 1. spring batch 메타데이터 데이터베이스 만들기데이터베이스 종류별로 spring batch schema를 만드는 sql이 있습니다.org.springframework.boot:spring-boot-starter-batch 의존성을 추..
react element는 값이 변하지 않는 상수이며, element 내용의 변경은 곧 새로운 element를 생성한다는 것을 의미한다. (re-render = re-create) children의 특징 매 렌더링마다 react element들은 새롭게 생성되고, 그로인해 object의 참조값이 변한다. 한번 전달된 prop은 상위 컴포넌트가 리렌더링되지 않는한 갱신되지 않고 이전 prop값을 재사용한다. 부모 컴포넌트는 children을 prop로 받으며 이때 children은 object형태인 상수다. 부모 컴포넌트가 리렌더링될때 children은 상수이므로 값이 달라지지 않아 리렌더링되지 않는다. children으로 전달되는 react element가 새롭게 생성되면 object의 참조값이 변경되므..
parallel + intercepting 라우트병렬 라우트와 함께 사용하면 모달에 대해 다음이 가능합니다:모달 콘텐츠를 URL을 통해 공유 가능하게 합니다.페이지를 새로고침할 때 모달을 닫는 대신 컨텍스트를 유지합니다.이전 라우트로 가는 대신 뒤로 이동하여 모달을 닫습니다.앞으로 이동하여 모달을 다시 엽니다.로그인 후 쉽게 직전 페이지로 이동할 수 있습니다.app디렉토리의 layout에 병렬 라우트(slot)을 prop로 추가합니다.이때 prop 이름은 병렬 라우트 디렉토리 이름과 같기만 하면 됩니다.루트 layout에 병렬 라우트를 추가해야 페이지에 나타나고, props로 사용할 수 있습니다. // app/layout.tsx export default function RootLayout({ chi..
모든 GrammarBook에서 각 book마다 연관된 Grammar 개수를 조회하는 기능이 있습니다. 해당 코드는 다음과 같습니다.@Transactional(readOnly = true)public List getGrammarNumOfAllGrammarBooks() { List responseDtos = new ArrayList(); for (GrammarBook grammarBook : this.grammarBookRepository.findAll()) { responseDtos.add( GrammarNumOfGrammarBookDto.builder() .id(grammarBook.getId()) .name(grammarBook.getN..
사용자가 문법 퀴즈를 풀고 틀린 문제를 저장하는 테이블(UserGrammarStatus)이 있습니다. 이 테이블에서 한 사용자가 틀린 모든 문법 문제를 조회하는 기능에서 N+1이 발생했습니다. 해당 기능은 아래 메서드이며, 사용자 이름으로 SiteUser 테이블에서 id를 찾아, UserGrammarStatus 테이블에서 해당 id의 grammar들을 조회합니다. @Transactional(readOnly = true) public WrongGrammarsResponseDto getUserWrongGrammars(String userName) { Long userId = getUserIdByUserName(userName); List userGrammarStatuses = this.userGrammarS..
“자바 ORM 표준 JPA 프로그래밍” 책으로 N+1에 대해 공부했습니다. 이후 기존 조회 로직들을 다시 테스트해보니 N+1 문제가 발생하는게 생각보다 많았습니다. 그래서 이것들을 모두 해결했고, 시리즈로 엮었습니다. 다음 코드는 Grammar 1개를 조회할때 연관된 GrammarBook과 GrammarExample까지 조회하는 service 메서드입니다. public GrammarDto getGrammar(Long id) { Grammar grammar = getGrammarById(id); return GrammarDto.builder() .id(id) .sentence(grammar.getSentence()) .grammarBookName(grammar.getGrammarBook().getName(..