728x90

분류 전체보기 173

Kotlin Spring 에서 Required = false 대신 ?(nullable) 을 사용가능한 이유

회사 코드를 짜다가 문득 생각이 하나 들었는데 Java 에서 @RequestParam(Required = false) 대신 Optional Long id 이런식으로 사용하면 동일하게 작동할 수 있다는 사실을 알고 있었다. 이것이 가능한 이유는 Spring Framework 의 RequestParamArgumentResolver 코드에 아래와 같은 코드가 존재한다. 여기서 중요한건 parameter.nestedIfOptional 인데 해당 Type 이 옵셔널인지 확인해주는 코드이다. 그래서 코틀린에서도 ?(nullable-type) 을 통해서 충분히 가능하지 않을까 생각하고 동일 위치에 디버그를 찍어보았다. 위의 디버깅 결과가 결론을 말해주는데 즉, 코틀린에서는 required = false 를 사용할 이..

Spring 2022.03.17

Hibernate 1 차 Cache 에 대해서 알아보자

Hibernate 에서는 데이터베이스의 부하를 줄이기 위해서 1차 캐시를 이용한다. 1차 캐시란 Transaction 내에서 작동하는 캐시를 뜻한다. 이 글은 위의 1차 캐시가 어떻게 작동하는지 알기에 본다고 생각하고, Hibernate 의 코드를 분석하는데만 신경을 쓸 것이다. 코드는 매우 간단합니다. @Service public class UserService { private final UserRepository userRepository; public UserService(UserRepository userRepository) { this.userRepository = userRepository; } @Transactional public void test() { User user = new Us..

Spring 2022.03.10

왜 계층간의 모델을 형성해야 하는가?

최근 읽었던 책 만들면서 배우는 클린 아키텍쳐와 그리고 리뷰를 하면서 받았던 질문들 중 "언제 DTO 를 사용해야 하나요? 혹은 왜 계층간 DTO 를 사용해야 하나요?" 라는 질문을 받은 적이 있다. 예전부터 한번쯤 정리해야지 했었는데, 이제는 글로 적어두는게 나을거 같아서 해당 내용을 글로 적어보려고 한다. 일반적인 우리의 서버 아키텍쳐는 아래와 같은 구조를 가지고 있을 것 이다. 우리는 보통 Repository 는 특정 외부 저장소 혹은 내부 저장소에 질의 하는 방법을 구현하고 있을 것이고, Service 는 우리가 수행해야 할 도메인(비즈니스) 로직을 구현하고 있을 것이다. Controller 계층은 외부세계에서의 요청을 받고, 내부세계에서 쓰기 좋게 외부세계로 부터 받아온 데이터 모델을 변환(Co..

Architecture 2022.03.07

[MySQL] ngram parser 를 이용할때 'a' 가 검색이 잘되지 않는 이유

이전에 ngram parser 를 이용한 자동완성 기능을 만들었다고 했었다. 실제로 적용해보니 문제가 있었는데 아래와 같은 문제가 발생했다. 위의 화면을 보면 'ach' 가 포함되어 있는 것만 검색하려고 BOOLEAN MODE 를 적용해서 쿼리를 날렸음에도 ach 가 없는 김루루 라는 콜럼이 검색되게 된다. 이유가 무엇일까? 문제 추론 처음에는 MySQL 의 Ngram Parser 의 Token size 를 1로 저장해놔서 아래와 같이 잘려서 그냥 알파벳만 들어가 있어도 검색이 되나 싶었다. 하지만 위와 같은 추론을 하기에는 무언가 연관성이 없어보였다. 왜냐하면 다른 글자로 검색을 해봤을때는 너무 잘 나오는 것이다. 이때까지만 해도 'a' 가 문제인줄을 몰랐다. 그래서 알아보던 도중 ngram parse..

MySQL 으로 형태소 분석기 없는 자동완성만들기

오늘은 간단하게 형태소 분석기 까지는 필요없는 자동완성 기능을 만들때 빠르게 만들 수 있는 방법을 해보려고 한다. 실제로 회사에도 적용한 방법이다 :) Ngram-Parser 를 택한 이유 일단 MySQL 에 ngram parser 를 이용한 방법인데 ngram parser 를 선택한 이유는 아래와 같았다. 첫째, 자동완성으로 검색되야 할 데이터 들이 MySQL 에서 관리되야 할 대상들이였다. -> 사실 NoSQL 로 가져가면 대표적으로 ES 형태소 분석 parser 나 빠른 검색등이 가능하다고 알려져 있으나 내 조건은 위와 같았다. 두번째, 딱히 ES 를 이것만을 사용하자고 추가하기에는 자원의 낭비이다. -> 굳이 MySQL 로도 가능한데 얼마 차이 안나는 성능때문에? 의문이다. 그리고 ROW 수가 적..

Spring 2022.02.24

Spring 에서 왜 Private Method 는 Cglib Proxy 에 포함이 되지않을까?

Spring 면접 하면 잘 등장하는 단골 질문 중 하나이다. 이 개념을 이해하기 위해서는 일단 Proxy 디자인 패턴에 대해서 간단하게 짚고 넘어가야 한다. 우리가 흔히 볼 수 있는 Server-Client 형태는 아래와 같다. Client 는 Server 에 요청을 보내고, Server 는 요청을 처리한다. 만약 객체 세상으로 가져온다고 했을때는 아래 그림처럼 A 객체가 B 객체에게 협력을 요청하는 것일 수 있다. 근데 만약 B 객체는 너무나 은밀한 친구라 중간에 누군가 자신이 한것처럼 대신 행동을 하는 척 해줬으면 좋겠다 라고 해보자. 그렇다면 A 객체는 B 객체와 이야기 하는것 같지만 사실은 대리자가 대신 해주고 있는 것으로 객체를 설계 해주어야 할 것이다. 위와 같은 설계가 될 것 이다. 하지만 ..

Spring 2022.02.22

Redis-Cluster 이미지 사용시 Redis-stat 쉽게 붙이기

Redis-Cluster 를 구축할때 아래 이미지를 많이 사용하는 것으로 알고 있다. grokzen/redis-cluster:6.0.5 도커에는 기본적으로 내부 IP 를 통한 통신을 할 수 있게 되는데 이것이 궁금하다면 docker0 Bridge 에 대해서 공부해보면 된다. 일단 여기는 삽질을 막는 내용만 적을 것이므로 docker0 Bridge 에 대해서 공부한 내용은 따로 적진 않겠다. docker 공식문서에도 잘 나와있으니 충분히 공부할 수 있을거라고 생각한다. 일단 가볍게 얘기해서 docker 간의 통신을 구축할때 docker 내부 접속 ip 를 알아야 할 때가 있었는데 이때 해결방법은 간단하게 같은 network 로 묶거나 혹은 host network 방식을 이용하거나 내부 접속 IP 를 알아낸..

Docker 2022.02.15

인덱스 컬럼의 가공(연산)은 예상치 못한 결과를 초래한다.

MySQL 2판을 보던 중 한가지 사실을 알았다. 바로 WHERE 조건문에 INDEX 를 통해서 검색하려고 할때 INDEX 에 변환 또는 연산을 가하게 될 경우 인덱스 조건을 안타게 된다는 사실이다. 아래 쿼리를 한번 보자. 지금 위의 쿼리를 한번 살펴보면 첫번째 쿼리는 age 라는 INDEX 컬럼에 2를 곱한 뒤 age=20 인 컬럼의 데이터를 가져오는 쿼리이다. 두번째 쿼리는 반대로 age = 40/2 인 즉 age = 20 인 쿼리를 가져오는 것이므로 두 쿼리의 결과는 아래처럼 똑같다. 하지만 결과는 같은데 MySQL 의 옵티마이저가 내린 판단은 다르다. 그 이유는 무엇일까? MySQL 에서는 기본적으로 정렬에 B-Tree 자료구조를 이용하는데 이때 사용자가 설정한 Index 의 값으로 정렬이 되어..

데이터베이스 2022.02.13

Redisson 을 분산 Lock 을 위해 사용한 이유

이전 포스팅에서 분산락에 관한 포스팅을 적었었는데 왜 Redisson 이라는 라이브러리를 사용했는지 적어보려고 한다. 일단 Spring-Boot-Starter-Redis 에서 사용하는 Library 는 Lettuce 라는 라이브러리를 사용한다. Lettuce 에서 Lock 을 구현할때는 스핀락 구조의 형태로 락을 많이 이용합니다. fun test() { val lockKey = "test" val lockTime = "3" val command = redisClient.connect().sync() try { // lock 을 획득하기 전까지 계속해서 Loop 를 순회 while (!command.setnx(lockKey, lockTime)) { // process } } catch (e: Excepti..

데이터베이스 2022.02.12
728x90