아래 코드 예시는 github에서 보실 수 있습니다 dependency testImplementation "org.testcontainers:testcontainers:1.17.3" testImplementation "org.testcontainers:junit-jupiter:1.17.3" testImplementation "org.testcontainers:mysql:1.17.3" Account 먼저 테스트에 사용할 Account Entity와 AccountService의 기본적인 CRUD 로직입니다 @Entity @Getter @NoArgsConstructor public class Account { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) ..
발단 인메모리 DB인 H2를 사용하여 로컬에서 통합 테스트를 구성했습니다. 하지만 해당 프로젝트의 서버 DB는 mysql이기 때문에 호환성 여부를 확인했습니다. H2에서는 Compatibility mode 를 지원하여 다른 DB 쿼리와 호환성을 제공하지만 100% 보장이 되지 않기 때문에 MySQL에서만 사용하는 특정 쿼리에 에러가 발생합니다. 그래서 로컬에서 서버 DB와 똑같은 MySQL를 통한 통합 테스트를 구성하면 괜찮을 것이라 생각했습니다. 하지만 해당 방법은 환경 세팅이 되어있지 않는 동료가 접하기에는 환경 세팅이 헤비할 수 있습니다. 독립적인 테스트 환경, 즉, 멱등성을 보장하기 위해 JUnit 테스트를 지원하는 Java 라이브러리인 Test Container를 알게 됐습니다. Test Con..
글을 쓰게 된 이유 YAPP 프로젝트 중 Account 삭제 기능을 맡았습니다. ( 토이 프로젝트이기 때문에 hard delete 진행) Account는 Club, Comment, Pet 등 대부분의 Entity와 연관관계를 맺고 있기 때문에 벌크 삭제를 했어야했습니다 그래서 어떻게 하면 최적화 된 벌크 삭제를 할 수 있을까라는 생각을 하게 됐습니다 이를 계기로 제가 알고 있는 delete 방법에 대해 정리해보고자 이 글을 작성했습니다 예제 코드 @Getter @NoArgsConstructor @ToString(of = {"id", "username", "age"}) @Entity public class Member { @Id @GeneratedValue @Column(name = "member_id")..
글을 쓰게 된 이유 YAPP 프로젝트를 진행하면서 제목을 통해 ‘모임 모집 글’을 검색하는 기능을 맡았습니다. 처음엔 기능 구현이 우선이었기 때문에 like를 통해 기능을 구현했습니다. 기능 구현을 모두 마무리하고, 리팩토링하는 과정에서 “만약에 게시글이 많아지고, 제목도 길어지게 되면 해당 쿼리는 엄청 오래 걸리지 않을까?”라는 생각이 들었습니다. 그래서 검색 성능 최적화를 하는 과정을 블로그에 적어보려고 합니다. 요구 사항 일반적인 검색과 같았습니다. 게시글에 제목이 있고, 사용자가 제목을 통해 검색하면 해당 단어가 포함되어있는 게시글을 조회하는 기능이었습니다. 초기 쿼리는 like %keyword% 로 날렸습니다. 테스트 상황 DB : MySQL, Elasticsearch 게시글의 데이터를 4999..
pr를 올리면서 commit log를 보니 이전 commit 과 중복되어 pr이 올라가있는 것을 겪었다 그래서 깔끔한 commit log를 만들고자 아래와 같은 실습을 해보았다 왜 중복이 됐을까? 화살표에서 나의 repo에 그대로 merge 했기 때문에 commit이 이전 commit과 쌓여서 중복이 된 것 같다 나의 repo master branch commit log 그래서 pr 올리는 레포의 pr을 날릴 때 , commit log를 보니 중복된 부분(a7670fb 시작) 이 쌓여서 pr이 날려진 것을 알 수 있다 그렇다면 실제로 반영되어야할 부분은 cc999fd, 9e23825, f9480f1인데 이를 어떻게 하면 좋을까? 결론을 먼저 말하자면 cherry-pick을 이용하여 해결할 수 있다 Do ..
cpu와 core는 어떤 차이가 있나요? CPU는 작업을 관리하고 실행하는 컴퓨터 시스템의 component로써 컨트롤러, 캐시 메모리, core로 이루어져있습니다. 코어가 실제로 작업을 처리하는 동안 CPU는 코어를 제어하고 다른 컴퓨터 시스템 컴포넌트의 데이터를 코어에게 전달합니다. 즉, core는 CPU의 일부로써, 컴퓨터에서 "실제로" 작업을 처리합니다. CPU CPU는 산술, 논리, 제어 및 입출력 작업을 수행하게 하는 명령을 수행하는 컴퓨터 내부의 전자회로입니다. 즉, CPU는 여러 요청 및 메시지를 사용 가능한 코어 간에 작업을 나누고, 코어는 CPU가 나눈 작업을 처리합니다. 결국 CPU는 산술, 논리 등과 같은 작업을 하라고 명령을 받는 것이고, 명령을 처리해주는 것은 코어라고 할 수 ..
vi 편집기로 md 파일을 작성 중에 줄바꿈이 제대로 이뤄지지 않아서 5번의 도전 끝에 성공했다 하지만 이러한 커밋 메시지는 이쁘지도 않고, 2,3,4,5는 그리 중요한 정보도 아니다 그래서 나는 위 커밋을 모두 하나의 커밋으로 합쳐보려고 한다!! git rebase -i [커밋 ID] fix : 1.6 줄바꿈이 제대로 수행되지 않음 의 커밋 ID를 가져온다 commit은 과거의 것부터 차곡차곡 쌓아올려져 있기 때문에 하나의 commit으로 합칠 때는 최근 것부터 합쳐야한다! 즉, 2,3,4,5 를 제일 오래된 commit에 합칠 것이다 git rebase -i 4a645679e545d8d650f10d50cbfc728eb753b6e5^ 해당 커밋 ID는 “fix : 1.6 줄바꿈이 제대로 수행되지 않음”..
YAPP 프로젝트를 진행하는 중에 현재 시간 기준으로 모임 종료 시간이 지났을 경우 모임을 종료시켜야 할 필요가 있었다 해당 기능은 스프링에서 제공하는 @Scheduled를 이용하여 구현할 수 있었다 스케줄러를 어떻게 사용했는지 기록한다 Implementation 현재 시간 기준으로 모임 종료 시간이 지났을 경우 모임을 종료시켜야 한다 How 모임 종료 시간이 현재 시간보다 지나있을 경우 모임의 status를 모임 종료로 변경 스프링에서 제공하는 스케줄러를 사용해보자! Scheduling 적용 @EnableScheduling SpringBootApplication이 붙은 클래스에 @EnableScheduling을 붙인다 @EnableJpaAuditing @SpringBootApplication @Enab..
MapStruct java mapping framework는 여러 가지가 있다 대표적으로 MapStruct와 ModelMapper가 있는데, 대부분 MapStruct를 사용한다 아래는 구글 트렌드에서 캡처한 자료 그 이유는 “속도” 차이가 월등히 나기 때문이다 ModelMapper는 매핑이 일어날 때 리플렉션이 발생 MapStruct는 컴파일 시점에서 annotation을 읽어 구현체를 만들어내기 때문에 리플렉션이 발생하지 않는다 (리플렉션은 구글링!) modelmapper는 변환할 때마다 맵핑할 객체를 계속해서 만들어내고(런타임), mapstruct는 빌드 시점에 구현체를 하나 만들어서 계속해서 그 구현체를 사용하기 때문에(컴파일) mapstruct가 더 시간이 빠르지 않을까? 그렇다면 MapStruc..
YAPP20기를 진행하면서 GitHub Actions + Docker를 이용하여 CI/CD를 구축하게 됐다 CI/CD를 해보고 싶었는데 마침 같이 BE를 맡으신 분은 이미 CI/CD를 경험해보셔서 나에게 맡겨주셨다 어떻게 진행했는지 기록하기 위해서 이 글을 써보려고 한다,, EC2, RDS 생성 이동욱 님의 “스프링 부트와 AWS로 혼자 구현하는 웹 서비스"라는 책을 보면서 했다 암호화 실제 배포하기 위해서는 property 파일에 RDS, Docker, IP의 ID, PW를 입력해야한다 이는 노출되면 안되기 때문에 “jasypt”라는 것을 이용하여 암호화를 해준다 이때 암호화 key는 우리가 나중에 Docker를 실행할 때 환경변수로 지정해주면 된다 참고 : jasypt 사용 spring: dataso..
yapp에서 주어진 단어가 게시글의 제목에 포함되있는지 판단하기 위해 like을 알게 됐다 하지만 like가 아닌 contains도 있었고, 이 둘의 차이가 무엇인지 궁금해서 테스트를 통해 확인해봤다 결론 like(str)은 쿼리가 나갈 때 str자체가 나간다 즉, 정확히 일치해야한다 like는 내가 % 연산을 선택할 수 있다 contains(str)은 쿼리가 나갈 때 %str%가 나간다 like 현재 Member 에는 member1, aamember1, aamember1aa, member1aa가 저장되어있다 @Test @DisplayName("like 확인") void like() throws Exception { List result1 = queryFactory .selectFrom(member) ...
throw와 throws는 메서드나 코드 block에서 예외를 명시적으로 던지는 자바의 예외 처리 방법이다 throw(파랑색) 메서드 내에서 사용됨 한 번에 하나의 예외만 발생시킬 수 있다 throw할 예외의 인스턴스 변수 사용 checked exception propagation 할 수 없음 unchecked exception만 propagation 할 수 있다 애초에 exception을 명시해주지 않으면 propagation이 일어나기 전에 complie 에러가 발생한다 throws(주황색) 메서드 signature에서 사용됨 쉼표로 여러 예외를 선언할 수 있다 throws할 예외의 클래스 이름을 쓴다 checked exception, unchecked exception propagate 할 수 있음..