본문 바로가기

SpringBoot

(11)
[SpringBoot] EAGER는 join 이 아니다 ✍🏻 글 작성의 계기어느덧 레벨3의 프로젝트를 진행하며 팀원들에게 fetchType 은 LAZY 로 하는 게 좋다는 말을 했다. 그러자 팀원들이 왜냐고 물었고, 한마디로 선뜻 정리하지 못하는 나를 발견했다. 그저 'EAGER 는 join 이 아니야..' 라는 애매한 말만 되풀이했다. 이후 내용을 정리해서 팀원들에게 이를 바탕으로 글 작성까지 하게 됐다. 🔎 이 글을 이런 분들께 추천합니다LAZY 로 매번 설정하긴 하는데, 왜인지는 솔직히 잘 모르겠다 하시는 분들매번 EAGER 는 join 이 되는 것이라고 생각하고 있는 분들EAGER 가 고려되는 상황블로그 서비스를 구현하고 있다고 가정해보자. Blog 는 게시글, BlogMember 는 작성자를 의미하며 Post 가 N:1 의 관계로 Member 를..
[SpringBoot] 💥 관습적인 EntityManager 의 clear 사용을 멈추세요 (feat. JPQL 과 1차 캐시) 🤔 궁금증을 갖게 된 계기 리뷰어 분과 대화를 주고 받다가, EntityManager 의 clear 를 사용한 이유에 대한 질문을 받았다. 이에 대해 나는 단순 지식 확인 측면이겠거니 - 하고 딱히 나의 지식을 더블 체크하지 않고 답변을 작성했었다. 나의 의도는 레포지토리의 코드가 제대로 동작하는지에 대한 검증을 하고자 하는 것이었다. 만약 EntityManager 의 clear 를 하지 않으면 실제 쿼리를 날리는 것이 아니라 1차 캐시를 확인해 쿼리를 날리지 않을 것이라고 생각했다. 그래서 작성한 대부분의 테스트 코드에서 습관적으로 EntityManager.clear 를 호출했다. 나름 확신이 있었기에 호기롭게 대답했다. 그런데 리뷰어의 답변은 다음과 같았다. 오싹한 기분이 들었다. 혹시 영속성 ..
[SpringBoot] 빈 등록과 생성은 다르다 (feat. BeanDefinition) 🕵🏻‍♀️ 궁금증을 갖게 된 계기학습 과정에서 다음과 같은 예시 코드를 마주하게 됐다.@Testvoid test3() { StaticApplicationContext context = new StaticApplicationContext(); context.registerBeanDefinition("printer", new RootBeanDefinition(Printer.class)); BeanDefinition helloDef = new RootBeanDefinition(Hello.class); helloDef.getPropertyValues().addPropertyValue("name", "Spring"); helloDef.getPropertyValues().addProp..
[SpringBoot] Presigned Url 을 이용해 S3에 이미지 업로드 하기 presigned url 이란?aws의 공식 문서pre(미리) signed(서명된) url 이라는 뜻으로 권한이 없는 사용자도 S3 버킷에 접근할 수 있는 권한을 부여하는 url 이다.왜 Presigned Url 을 사용해야 할까?기존의 이미지 등록 방식은 위와 같았다. 클라이언트는 서버에 직접적으로 이미지 파일을 전달하고, 서버는 이를 s3 에 전달해 이미지를 저장했다. 그러나 이는 이미지 파일을 직접 서버에 전달하기 때문에 서버에 부하가 발생할 수 있다.그러나 presigned url 을 사용하면 S3 에 클라이언트가 직접 접근하여 이미지를 업로드 할 수 있다. 즉, 서버가 이미지 파일을 전달할 필요가 없어지므로 부하가 줄어든다.S3 에 클라이언트는 이미지 파일을 저장하고, 이미지 url 만을 서버에..
[SpringBoot] 도메인 이벤트를 알아보고 AbstractAggregateRoot 를 이용해 채팅 서비스를 구현해보자 https://dev-seunghee.tistory.com/12 [SpringBoot] 이벤트 기반 아키텍처를 알아보고 스프링부트의 이벤트를 구현해보자📝 들어가며 교내의 스포츠 경기 상활을 실시간으로 확인할 수 있는 서비스 '훕치치'에서는 사용자들이 응원하는 팀에 대해 응원 댓글을 남길 수 있는 기능을 제공하고 있다. 1차 릴리즈 이후dev-seunghee.tistory.com위의 글에서 이어집니다!앞선 게시글에서 '이벤트' 자체란 무엇이고, 스프링부트에서 이를 어떻게 구현할 수 있는지에 대해서 알아봤다. 프로젝트의 구현 상황에 따르면 이벤트 기반 아키텍처를 사용하는 것이 옳을 것으로 보인다. 이는 이벤트를 사용하기도 하지만, 동시에 도메인 자체의 변화와도 같다. 왜냐하면 사용자가 남긴 채팅은 일일이 ..
[SpringBoot] 이벤트 기반 아키텍처를 알아보고 스프링부트의 이벤트를 구현해보자 📝 들어가며 교내의 스포츠 경기 상활을 실시간으로 확인할 수 있는 서비스 '훕치치'에서는 사용자들이 응원하는 팀에 대해 응원 댓글을 남길 수 있는 기능을 제공하고 있다. 1차 릴리즈 이후 서비스에 대한 피드백을 받았을 당시, 새로고침을 해야만 새로운 댓글이 반영되는 것에 대한 지적이 있었다. 이전까지는 '댓글'에 가깝게 해당 기능을 정의했지만, 해당 피드백과 이벤트 스토밍을 통해 도메인 용어를 정리한 뒤에는 해당 기능이 '채팅'에 가깝다고 정의를 내리고 '응원톡'이라고 명명하기로 했다. 따라서 실시간으로 새로 등록된 댓글이 반영되는 것으로 기획이 바뀌어 새로 구현을 하게 됐다. 그 과정 중에서도 이번에는 이벤트 기반 아키텍처란 무엇이며, 왜 이 기능의 구현 과정에서 이벤트 기반 아키텍처를 사용했는지 그리..
[SpringBoot] Spring REST Docs 로 API 명세를 문서화 하자 💭 들어가며 최근, 이벤트 스토밍을 팀원들과 하며 대대적인 리팩토링을 진행했다. 이벤트 스토밍 구경하러 가기 훕치치의 이벤트 스토밍 이벤트 스토밍 소개 및 경험 공유 hufscheer-techblog.vercel.app 도메인 용어들을 대다수 변경하다 보니, 엔드포인트도 다수 변경되었는데 해당 변경사항들을 모두 일일이 노션에 기입하려니 불편함과 불안함이 생겼다. 작성한 API 스펙이 맞는지 헷갈렸고, 팀원분과의 상의를 통해 API 문서화를 할 수 있는 Spring REST Docs 를 도입하기로 했다. 💬 Spring REST Docs 의 전체적인 플로우 우선, 전체적인 플로우에 대한 이해를 먼저 하고 난 뒤에 코드를 살펴보면 더 빠른 이해가 가능할 것 같아 플로우를 먼저 짚어보자. 1. 테스트 코드를 ..
[SpringBoot] 동시성 문제를 해결하자 (Synchronized, MySQL, Redis) 💭 들어가며 진행하던 프로젝트에서 위와 같이 응원 횟수를 여러번 클릭하면 이에 맞게 횟수가 증가되는 로직을 구현해야 했다. 한 명의 사용자는 여러번 응원 횟수를 증가시킬 수 있다. 이와 관련해 어떻게 동시성 문제를 해결할 수 있을지에 대한 고민을 시작했다. ✅ 동시성 문제란? 동시성 문제가 발생하지 않는 상황 pk가 1인 응원 데이터의 응원 횟수가 90인 상태에서 사용자 A 가 3번 응원 횟수를 증가시키고 사용자 B 가 10번 응원 횟수를 증가시켰다고 가정해보자. 사용자 A 응원 횟수 사용자 B pk가 1인 응원 데이터를 찾는다 >> 아 응원 횟수는 90이구나! 90회 pk 가 1인 응원 데이터의 횟수를 3회 증가시킨다. 93회 93회 pk가 1인 응원 데이터를 찾는다 >> 아 응원 횟수는 93이구나!..