본문 바로가기
반응형

Develop235

[DB] 'is not NULL'과 '!= NULL'은 다르다? 팀원분이 비슷해 보이는 두 쿼리문를 보내시며 둘의 결과가 서로 다르다고 보내주셨다. 두 쿼리의 차이점은 오직 NULL 체크를 is not NULL로 하냐, != NULL로 하냐의 차이였다. 쉬운 이해를 위해 사용자를 조회하는 쿼리가 있다고 가정해보겠다. -- 1: is not NULL 사용 (10 Results) select * from member where age is not NULL limit 1; -- 2: != NULL 사용 (0 Results) select * from member where age != NULL limit 1; is not NULL에서는 조회 결과가 있지만, != NULL에서는 조회 결과가 없었다. 왜 그럴까? SQL에서는 NULL 값을 =, 같은 비교 연산자를 이용해 비교할.. 2023. 6. 7.
[Spring] 스프링 캐시 간단하게 사용해보기 목차 1. 스프링의 캐싱 방법 2. 사전 준비 3. 예제 코드 1. 스프링의 캐싱 방법 캐싱 자주 사용하는 데이터를 어딘가 임시로 저장하고, 빠르게 꺼내 쓰기 위해 사용할 수 있게 하는 프로세스 서버의 부담을 줄여 성능을 높이기 위해 사용하기도 함 ex: DB에서 조회하는게 굉장히 오래 걸리는 데이터를 캐싱해두면, 다음에 조회할 때 DB의 조회 결과를 기다리지 않고 캐싱 영역에서 빠르게 가져다 쓸 수 있음 스프링의 캐싱 @Cacheable, @CacheEvict 같은 어노테이션을 통해 AOP 기반으로 동작 이를 위해서는 @EnableCaching 설정이 필수 2. 사전 준비 이 글에서는 Redis를 이용해 예제 코드를 작성하기 때문에 사전 준비가 필요하다. 별도의 Redis를 사용하지 않는 경우에는 생략.. 2023. 5. 31.
[Spring] '/', 문자열인가 경로인가 그것이 문제로다 🤔 문제의 시작 API를 호출하면 json이 아닌 html 코드로 응답이 오고 있다는 이슈를 제보받았습니다. 해당 html 코드를 열어보니 아래와 같이 HTTP 상태 코드 400을 보여주고 있었습니다. 상태 코드 400은 Bad Request라는 의미로, 클라이언트의 요청이 잘못되어 서버가 요청을 처리할 수 없거나 처리하지 않을 것임을 나타내는 코드입니다. 🧐 원인 분석 문제가 발생하는 정확한 케이스를 파악하기 위해 현상 재현을 시도하였습니다. API를 호출해봤더니 애플리케이션에 요청이 들어오지도 않는 것처럼 보였습니다. 400이라는 응답값만 생각해보면 어디선가 예외가 발생했을 것 같은데, 예외가 발생했다는 에러 로그가 남지 않았거든요. 어떤 API인지 설명하기 위해 가상의 예제 API를 만들어보았습니.. 2023. 5. 12.
[HTTP] Accept-Charset은 왜 deprecated 되었나 1. Accept Charset 설정 HTTP 헤더의 Accept에 "application/json;charset=UTF-8"값을 넣기 위해 아래와 같은 코드를 작성했다. 여기서 Accept는 클라이언트가 처리할 수 있는 미디어 타입을 알리기 위해 사용한다. IntelliJ가 노란 줄로 표기해 주면서 deprecated 된 코드임을 알려주었다. HttpHeaders headers = new HttpHeaders(); headers.setAccept(List.of(MediaType.APPLICATION_JSON_UTF8)); deprecated 된 사유에 대해 친절하게도 Spring이 주석을 달아두었다. 아래와 같은 내용이 적혀있었다. Deprecated as of 5.2 in favor of APPLIC.. 2023. 5. 2.
[Kotest] 오버로딩한 메서드 테스트하기 (feat: slot) 현재 우리 팀에서는 모종의 이유로 애플리케이션 코드는 Java, 테스트 코드는 Kotest로 작성하고 있다. 오늘은 테스트 코드를 작성하다 겪은 일에 대해 작성할 예정이다. (예제 코드는 문제 상황과 유사하게 만든 코드일 뿐, 실무 코드와는 관련이 없습니다.) 자바에서는 한 클래스 내에서 이름이 같은 메서드를 중복으로 정의할 수 없다. 하지만 '메서드 오버로딩'을 통해 매개변수의 개수나 타입 등을 다르게 하면 같은 이름의 메서드를 작성하는 것이 가능하다. 메소드 내부 구현은 상황에 따라 달라지겠지만 오늘은 아래와 같은 코드에 대한 테스트 코드를 작성하려고 한다. public class Order { public void order(OrderRequest orderRequest) { order(orderR.. 2023. 3. 5.
[Java] 스프링 부트를 제거해서 생긴 일 😄 개요 깃허브 프로필에 블로그 최신 포스트를 업데이트 시켜주는 간단한 토이 프로젝트를 만들었다. (현재 이 프로젝트는 최소한의 기능만 만들고 업데이트를 중단하고 있다. 나중에 회사 적응이 끝나고 시간적으로 여유가 난다면.. 다시 개선할 예정이다.) 처음에는 Spring Boot를 이용하다가 최대한 간소화 시키기 위해 제거했다. 그 과정 중에서 겪은 오류에 대해서 정리해보려 한다. 자바만으로도 당연히 되겠지, 라고 생각했던 기능 중 알고보니 스프링/스프링 부트가 담당했던 기능! 을 기억해두기 위한 포스팅이다. 👿 jar 파일에서 클래스를 못 찾는다? GitHub Action 스크립트를 작성할 때 jar 파일을 생성하고, 이 jar 파일을 실행하는 형식으로 만들었다. Spring을 적용했을 때는 무사히 동.. 2023. 2. 5.
[Java] replaceAll 대신 replace 사용하기 🙂 개요 String에서 흔히 사용하는 메서드 중에서는 replaceAll라는게 있다. 다들 알다시피 replaceAll은 특정 문자를 다른 문자로 대치할 수 있게 해주는 아주 편리한 메서드이다. 그러다 replaceAll보다는 replace를 사용하는 것이 좋다는 이야기를 듣게 되어 사실인지 살펴보기 위해 해당 포스팅을 작성하게 되었다. 🤓 간단 테스트 먼저 replace에 대해 흔히 하는 오해를 바로 잡고 가야한다. replaceAll 메서드가 따로 있다보니 replace는 일치하는 첫 부분 또는 일부만 대체해 주는건가? 라고 착각할 수 있다. 예를 들어 A를 B로 대체한다고 가정할 때, AA가 BA로 대체될 거라고 착각한다. 하지만 실제로는 BB로 대체된다. (참고로 여러 일치하는 문자열 중 첫 부.. 2023. 1. 22.
[Java] 동시성 이슈 해결하기 (1) 같은 계좌를 이용하는 A와 B라는 이용자가 있다고 가정한다. 동일한 시간에 A는 카드를 이용해 상품을 결제했고, B는 은행 어플을 통해 계좌이체를 했다. 대략의 플로우를 상상해보면 아래와 같다. A와 B는 같은 시간에 잔액을 조회했다. A는 40,000원을 결제하여 계좌에 남은 잔액인 60,000원을 반영하였다. 같은 시각, B는 20,000원을 계좌 이체하였다. B의 처리 속도가 약간 늦어져 A가 계산된 금액 반영을 한 뒤에야 B의 계산된 금액을 반영했다. 한 계좌에서 각각 40,000원과 20,000원이 결제되었으니 잔액은 40,000원이 남아야한다. 하지만 현재 80,000원이 남은 상태임을 확인할 수 있다. 이는 계좌라는 같은 자원에 여러 사람이 동시에 접근하기 때문에 발생하는 문제이다. 다양한 .. 2022. 12. 9.
[Spring/AOP] JDK Dynamic Proxy vs CGLIB Proxy 목차 JDK Dynamic Proxy vs CGLIB Proxy JDK Dynamic Proxy CGLIB Proxy JDK Dynamic Proxy vs CGLIB Proxy Spring AOP와 proxy Spring에서 사용하는 proxy Spring Boot에서 사용하는 proxy 왜 진작 CGLIB을 이용하지 않았을까? 1. JDK Dynamic Proxy vs CGLIB Proxy 💣 Spring에서는 프록시를 이용해 AOP를 지원한다. (AOP를 모른다면 이 링크를 참고하자. Spring의 대표적인 AOP인 @Transactional과 AOP에 대한 간략한 설명을 담았다.) JDK Dynamic Proxy, CGLIB 두 가지 방식을 사용하는데 왜 프록시 종류가 2가지나 있는지, 언제 어떤 .. 2022. 11. 23.
반응형