본문 바로가기

전체 글

(18)
[Real MySQL] 아키텍처 MySQL 엔진 아키텍처 MySQL 엔진 커넥션 핸들러: 클라이언트로부터의 접속을 처리한다. 파서: 클라이언트로부터 들어온 쿼리 요청을 처리한다. 옵티마이저: 쿼리의 최적화된 실행을 도와준다. 스토리지 엔진 실제 데이터를 디스크 스토리지에 저장하거나 디스크 스토리지로부터 데이터를 읽어오는 역할을 담당한다. MySQL 서버에서 MySQL 엔진은 하나지만 스토리지 엔진은 여러 개를 사용할 수 있다. CREATE TABLE test_table(cal1, cal2, ...) ENGINE=INNODB; 핸들러 API 데이터를 읽거나 쓸 때 MySQL 엔진에서 스토리지 엔진으로 요청을 보내야 하는데, 이 때 사용하는 API를 핸들러 API라고 한다. MySQL 스레딩 구조 MySQL 서버는 프로세스가 아닌 스레드 ..
[클린코드] 의미 있는 이름 의도를 분명히 밝혀라 의도가 드러나는 이름을 사용하면 코드 이해와 변경이 쉬워진다. 코드가 단순한게 문제가 아니다. 코드를 통해 명확히 어떤 의도로 사용되는 것인지 짐작할 수 있어야 한다. 그릇된 정보를 피해라 널리 쓰이는 의미가 있는 단어를 다른 의미로 사용하면 안된다. 서로 흡사한 이름을 사용하지 않도록 주의해야 한다. 유사한 개념은 유사한 표기법을 사용한다. 알파벳 "O", "l" 처럼 숫자와 혼동될 수 있는 변수 명을 주의해서 사용해야 한다. 의미 있게 구분하라 불용어를 추가한 이름은 아무런 정보도 제공하지 못한다. Product라는 클래스가 있을 때, 다른 클래스를 ProductInfo, ProductData로 사용한다면 의미가 불분명한 정보라 이해하기 쉽지 않다. 불용어 : 문장 내에서 빈번하..
불필요한 객체 생성 막기 현재 이메일을 검증하는 기능은 ConstraintValidator를 구현한 EmailFormatValidator에서 수행하고 있다. 그리고 이메일 검증 메소드는 다음과 같이 구현되어 있다. @Component public class EmailFormatValidator implements ConstraintValidator { // ... private static boolean validateEmailAddress(Email email) { return !Pattern.matches(RegexConst.EMAIL_VALID_REGEX, email.getAddress()); } } 정규식으로 올바른 이메일인지 검증하기 위해서 Pattern.matches() 메소드를 사용하고 있는데, 해당 메소드의 코드는..
객체지향적으로 중복 검증 로직 제거하기 (feat. @Embedded) 문제 사용자인 User는 로그인ID를 가지고있다. 현재는 이 값들을 String 타입으로 표현하고 있지만, 이렇게되면 다음과 같이 동일한 검증 로직이 중복되는 문제가 발생한다. 현재 로그인 ID를 검증하는 기능은 여러 API에서 이루어진다. // 1. 회원가입 API @PostMapping("/signup") public ResponseEntity signup( // SignupRequest 내부에서 loginId에 대한 검증이 이루어짐 @RequestBody @Valid SignupRequest signupRequest, HttpServletRequest httpServletRequest ) { Long savedUserId = userService.signup(signupRequest); return..
커스텀 ArgumentResolver를 구현하여 세션에 의존적인 파라미터 의존성 제거하기 문제 현재는 세션 로그인 방식을 사용하고 있다. 따라서 로그인된 사용자에 대한 정보를 가져오기 위해서는 세션에 저장된 사용자의 정보를 가져와야 했다. 세션에 저장된 사용자의 정보를 가져오기 위해 @SesseionAttribute 어노테이션을 사용하였다. @LoginCheck(authority = UserAuthority.USER) @PostMapping public ResponseEntity createAuthor( @RequestBody @Valid AuthorCreateRequest authorCreateRequest, @SessionAttribute(value = UserSessionUtil.LOGIN_MEMBER_ID, required = false) UserAuthDTO userAuth, Htt..
@Async 파해치기 최근 프로젝트에서 비동기로 메소드를 처리하여 응답 속도를 높이기 위해 @Async 어노테이션을 사용한적 있었다. 하지만 기능 구현에 급급해 @Async가 어떻게 동작하는지, 주의할 점은 무엇인지 알지 못한 채 단순히 어노테이션을 적용만했기 때문에 동작 과정을 살펴보기로 했다. 우선 간단히 어떻게 동작하는지 살펴보자 우선 @EnableAsync 어노테이션을 Application 클래스 위에 붙여준다. 그리고 위와 같이 비동기로 처리하려는 메소드에 @Async 어노테이션을 적용하면 된다. 위 코드로 메소드를 만약 동기적으로 호출한다면 start test method 출력 end test method 출력 service start 출력 위 순서대로 콘솔에 출력되어야 한다. 하지만 testService.test..
조회 성능 개선기 - 2 웹툰 서비스 프로젝트를 진행 중 실시간 웹툰 목록 조회 기능의 성능을 개선할 필요성을 느꼈다. 메인 페이지에서 자주 조회되는 기능이고 웹툰(comic) 테이블에 조회수에 대한 정보를 따로 담고있지 않기 때문에 웹툰별 조회수를 조회하기 위해서는 view 테이블의 로우 수를 count 해줘야 했다. 대략적인 테이블 구조는 다음과 같다. 실시간 인기 웹툰 목록 조회 실시간 인기 웹툰 목록 조회 기능은 0시부터 2시, 2시부터 4시, … 22시부터 24시까지 2시간 간격으로 각 웹툰마다 조회수를 계산하고 현재 시간보다 이전 시간 중 가장 가까운 시간의 조회수 합을 기준으로 10개의 웹툰을 조회한다. 즉, 현재 시간이 오전 2시 1분이라면, 0시부터 2시까지의 웹툰별 조회수 누적 합을, 현재 시간이 17시 30분..
조회 성능 개선기 - 1 장르별 조회 기능 개선 기존 장르별 조회 기능의 SQL 쿼리는 다음과 같다. SELECT c.id, c.name, a.author_name, t.image_url, c.created_at > "..." FROM comic c LEFT JOIN episode e ON e.comic_id = c.id AND e.episode_number = (SELECT MAX(e2.episode_number) FROM episode e2 WHERE e2.comic_id = c.id) LEFT JOIN view v ON e.id = v.episode_id JOIN author a ON a.id = c.author_id LEFT JOIN thumbnail t ON c.id = t.comic_id AND t.thumbnail_..