Spring Boot
문제 상황 태그 테이블을 리팩토링하면서 태그 리스트를 String으로 받도록 변경하였다. @NotNull(message = "아이템 태그는 빈칸일 수 없습니다") private String itemTagList; 문제는 이렇게 변경할 경우 태그 기반 검색을 수행할 때 기존의 like로 조회 시 극심한 성능 저하가 에상된다는 점이다. 이 때의 상황에 대비하여 멘토님께서 조언해주신대로 MySQL의 full text search를 적용해보았다. 해결방법 Full Text Search란? Full text search는 MySQL을 사용한다면 하나의 서비스나 시스템에 대해 데이터 저장, 관리, 저장된 데이터 내에서의 간단한 검색 기능을 제공할 때 사용 elastic search 같은 검색 엔진을 사용하지 않더라..
상황 좋아요 테이블 반정규화 그 전 글을 통해 좋아요 기능을 구현할 때 테이블을 어떻게 설계해야할지에 대해 많은 고민을 했다는 사실을 알 수 있을 것이다. 좋아요를 구현할 때 좋아요 테이블을 만드는 것은 당연하다. 하지만 그 좋아요가 여러 개에 해당할 때에는? 테이블을 어떻게 해야할 것인지에 대해 많은 고민을 하였다. 결국 나는 테이블을 나누는 정규화 대신, 반정규화를 이용하여 테이블을 합쳤다. 데이터 중복을 견디고 조회 성능을 선택하다.. 태그 비슷한 예시로 태그가 있다. 예비부부, 플래너, 포트폴리오, 아이템에서 태그를 참조하고 있다. 기본적으로 N:M 관계이기 때문에 현재는 중간테이블을 두어 태그 테이블과 연결하는 방식을 사용하였다. 하지만 이는 과도하게 테이블이 많아지는 결과를 초래하고 성능 향상..
문제 상황 내가 개발을 맡았던 좋아요 기능에서 내가 봐도 문제가 많은 코드가 있었다. 부끄럽지만 이를 공개하자면.. /*================== User가 좋아요 한 Entity 리스트 반환 ==================*/ public List getUserLikedPortfolio(Users users) { List likeList = likesRepositoryService.getLikesByUsersAndType(users, LikeEnum.PORTFOLIO); return likeList.stream() .map(userLikes -> portfolioRepositoryService.findPortfolioById(userLikes.getLikedId())) .filter(portf..
멘토링 중 멘토님께서 지적해주셨던 내용! GET 메소드 일 때에는 readOnly=true를 붙이라고 말씀해주셨는데 이는 Transactional에서 readOnly=true를 사용하면 다음과 같은 이점이 있기 때문이다. 1. JPA와 관련된 이점 1. 트랜잭션 Commit 시 영속성 컨텍스트가 자동으로 flush 되지 않으므로 조회용으로 가져온 Entity의 예상치 못한 수정을 방지 2. JPA는 해당 트랜잭션 내에서 조회하는 Entity는 조회용임을 인식하고 변경 감지를 위한 Snapshot을 따로 보관하지 않으므로 메모리가 절약되는 성능상 이점 2. Replication 부하 분산 readOnly = true가 설정되어있는 메서드의 경우 Slave DB에서 데이터를 가져오도록 동작한다. 이를 통해 ..
문제 상황 서비스 개발 중 여러 쓰레드에서 발생하는 작업에 대한 처리가 필요한 상황이 있습니다. 사실 우리 서비스는 아주 영세..해서 여러 사용자들의 동시 요청에 대한 처리를 할 필요는 없는데요. 하지만 학습은 좋은거니까..^^ redis에 대해서, 그리고 데이터 원자성을 보장하는 방법에 대해 공부할 겸 redis를 사용한 분산락을 구현하였습니다. 락(Lock)을 구현하는 방법 고유락/모니터락 자바는 멀티스레드 환경에서 동기화를 지원하기 위해 가장 기초적인 장치인 고유락(Intrinsic Lock)을 제공합니다. Java의 synchronized 키워드가 이의 예시이며 synchronized 블록은 객체 단위로 락을 다룹니다. Portfolio Entity에 synchronized 으로 락이 걸린 메소드..
좋아요 기능 구현 : RDB vs Redis redis로 구현 시 실시간성이나 동시성에 대해 처리가 쉽고 구조가 간단하다는 장점이 있지만 데이터 유실과 용량에 대한 부분이 우려스럽고 또 rdb는 데이터가 안정적이나 속도가 느린 것이 걱정되어 멘토님들께 의견을 구하였습니다. 현실적인 답변드리자면, 현재 유저의 규모가 크지 않기 때문에 RDB만 사용해서 구현하는게 좋습니다. 만약 데이터가 많다면, redis를 쓰더라도 데이터 정책 설정하기 나름이긴한데, 저라면 좋아요 데이터자체는 RDB에 저장하고, 게시글마다 좋아요 수 같은 통계데이터는 redis에 캐싱할듯하네요. 말씀하신 것처럼 각각의 장단점을 명확합니다! 잘 파악해주셨네요! 사실 트래픽이 크지도 않고, 데이터가 많지도 않을 것이기 때문에 rdb도 절대 ..
문제 상황 개발을 하다보면 코드 성능을 측정해야하는 경우가 생깁니다. 그리고 가장 보편적인 경우는 코드의 수행시간을 측정하는 것입니다. 기존에는 직접 코드 내에 성능 측정 로직을 작성하여 이를 측정하고 있었습니다. @Test public void testLikeRepositoryFindByUsersAndLikeTypeAndLikedId() { Users users = usersRepository.findByNickname("test0").get(); long startTime = System.currentTimeMillis(); likeRepository.findByUsersAndLikeTypeAndLikedId(users,LikeEnum.ITEM, Long.valueOf(1)); long endTime..
문제 상황 Spring Boot로 개발을 진행하던 중 random한 list를, 그것도 filter를 적용한 list를 page로 직접 변환해야 하는 일이 생겼다. JPA는 pageable을 사용하여 손쉽게 pagination을 적용할 수 있게 해주지만 내 경우에는 list를 page 객체로 직접 변환해야 했기 때문에 구글링을 좀 했어야 했다. 해결 방법 결론적으로 그 방법은 List를 하나 정의 한 후, List fileList = new ArrayList(); fileList를 생성 후 반복문을 돌면서 list에 원소를 추가한다. fileRepository.findAll().forEach(file-> { if (file.getItem() != null) { if (Boolean.FALSE.equals..