개발 일지 168

[SQL] ANSI Join

SQL 문법을 공부하던 도중, 대부분의 문법은 비슷하지만 MySQL과 Oracle에서 사용되는 구문에서 조금 차이가 있다는 점을 알게 되었다. 그럼 각각의 데이터베이스에 대한 구문 정보를 모두 알아야 하나? 물론 모두 알아두면 좋겠다만, 조금 비효율적이라는 생각이 든다. 또한 MySQL로 작업하다 Oracle로 DB를 변경해야 하면 다 찾아서 변경해야되는데 여간 번거로운 일이 아닐 것이다. ANSI 조인은 위와 같은 상황에서 아주 유용하게 쓰일 것이다. ANSI 조인이 뭔데? ANSI 조인은 데이터베이스에서 테이블을 결합할 때 사용되는 표준 SQL 문법 중 하나이다. 이러한 조인은 명시적으로 조인 조건을 정의하여 테이블을 연결한다. SQL 표준이기 때문에 여러 데이터베이스 시스템에서 지원된다. 그러니까 ..

개발 일지/SQL 2023.08.01

Queue 자료구조에서 add와 offer의 차이

Java에서 Queue 인터페이스를 사용하는 도중 add와 offer는 같은 동작을 하는 것 같은데, 왜 분리되어 있는 걸까? 라는 생각이 들었다. 보통 Queue는 LinkedList 자료구조를 활용하기 때문에 LinkedList 에서는 어떻게 구현하고 있는지를 확인해봤다. ..? 소스 코드로 구현 원리를 파악할 수는 있지만 offer도 결국 add를 사용하는 것처럼 보였다. add와 offer가 분리된 명확한 이유를 모르겠어서 구글링의 단계로 돌입했다. add와 offer의 차이 우선 'add'와 'offer' 모두 요소를 컬렉션에 추가하는 데 사용된다. 그럼 차이는 뭘까? 'Collection' 인터페이스에서 'add' 메서드의 반환 값은 항상 'true'이다. 따라서 Queue 인터페이스를 구현한..

개발 일지/etc 2023.07.31

[Java] serialVersionUID

Java에서 serialVersionUID는 직렬화(serialization)와 관련된 필드이다. 직렬화는 객체를 바이트 스트림으로 변환해서 저장하거나 네트워크를 통해 전송하는 과정을 말한다. 이렇게 직렬화된 객체는 나중에 역질렬화(deserialization)해서 원래 객체로 복원할 수 있다. 하지만 클래스의 구조가 변경되거나 버전이 업데이트된 경우에 문제가 발생할 수 있다. 이 때 'serialVersionUID'를 사용해서 객체 버전을 명시적으로 관리하는 것이다. serialVersionUID의 목적 serialVersionUID는 직렬화된 객체의 버전 번호를 나타낸다. 객체가 직렬화되면 버전 번호가 함께 저장되며, 역직렬화될 때 같은 버전 번호를 가진 클래스로만 역직렬화가 가능하다. 이는 클래스의..

개발 일지/Java 2023.07.29

SQL 공부의 필요성

학습 이유 그동안 Spring Boot 기반의 프로젝트를 진행하면서 JPA를 사용했기 때문에 별도로 SQL문을 작성하지 않아도 데이터베이스 조작이 가능했다. 또한, 프로젝트에서 기본 CRUD에 대한 작업만 진행했어서 JPA의 한계점이라던가 SQL 문법의 필요성을 느끼지 못했던 것 같다. 하지만 프로젝트 기간이 끝나고 유지보수를 위해 코드를 살피는 도중 N+1 문제가 발생하는 것을 확인했고, 주요 도메인에는 1:N 관계의 테이블이 많아서 (구글링하면 나오는 일반적인 방법들)fetch join이나 @EntityGraph로는 해결할 수 없었다. 그래서 QueryDSL을 공부해서 해결하려고 생각중이었다. 그리고 JPA는 편리한 기능을 제공하긴 하지만 대량의 데이터를 처리하거나 복잡한 쿼리를 실행하기에는 한계가 ..

개발 일지/SQL 2023.07.14

[JPA] N+1 문제에 대해서

위 로직은 이력서 도메인과 1:N 관계의 entity들이다. 1개의 이력서에는 기술 스택, 교육 사항, 프로젝트, 경력 등을 여러 개 입력할 수 있다. 여기서 하나의 이력서(CV)를 조회할 때, N+1 문제가 발생하는 것을 확인했다. 로그를 보면, 하나의 이력서(CV)를 조회하는 쿼리가 날아가고 추가적으로 연관된 객체들이 조회되는 것을 확인할 수 있다. 만약 여러 개의 이력서를 조회한다고 가정하고 이력서의 개수가 N개라면 N * (1 + 8)개의 쿼리가 발생한다. 극단적으로 예를 들면 10000개의 이력서가 있고 findAll()로 이력서들을 조회하면 90000개의 쿼리가 발생할 것이다. 따라서 1번의 쿼리에 N번의 쿼리가 추가 실행되므로, 쿼리 실행 횟수가 증가하여 성능에 부담을 주고 데이터베이스에 부..

Service 로직에서 List를 다룰 때 발생하는 index 문제 해결

프로젝트에서 맡은 이력서 CRUD 작업의 기본 로직을 다 만들어 두고 추가로 수정할 부분이 없나 하고 찾아보다가 문제를 하나 발견했다. Postman으로 여러 데이터를 입력해보고 테스트를 진행했을 때는 발생했던 오류가 아니어서 작업하면서는 찾지 못했던 것 같다. 기존에 작성했던 코드는 다음과 같다. 이력서를 수정하는 코드 안에 포함된 로직이다. 이 로직을 추가한 이유는 사용자가 이력서를 수정할 때, 기존의 이력서에는 경력사항이나 프로젝트 등이 들어가 있었지만 해당 데이터들을 지우거나 수정한 경우에 수정된 이력서에 들어가 있는 경력 사항 등만 두고 기존의 데이터는 지우려고 했기 때문이다. 테스트를 할 때는 저 로직에서 발생하는 예외상황을 생각하지 못했었는데, 위 remove에서 밑줄 그인 부분이 신경쓰여서..

함수형 인터페이스 - Supplier와 Consumer

프로젝트에서 작성한 코드를 리팩토링할 방법을 찾다가 Supplier와 Consumer라는 함수형 인터페이스를 찾게 되었다. 함수형 인터페이스(Functional Interface)는 단일 추상 메서드를 가지고 있는 인터페이스로, 람다식이나 메서드 참조를 활용해서 함수형 프로그래밍을 지원한다. Supplier Supplier는 매개변수가 없고 값을 반환한다. get() 메서드를 호출해서 값을 생성하거나 가져올 수 있다. 일반적으로는 데이터를 생성하거나 외부에서 값을 가져오는 용도로 사용하며, 'Supplier 변수명'으로 선언하고 그에 따른 람다식을 작성하면 된다. 예를 들어, Supplier는 정수 값을 생성하고 Supplier은 문자열 값을 가져올 수 있다. Consumer Consumer는 매개변수를..

개발 일지/Java 2023.06.24

REST API 의 GET 요청에는 Request Body를 넣을 수 있을까?

REST API의 GET 요청은 서버로부터 리소스를 조회하거나 검색하기 위해 사용되며, 보통은 요청 매개변수(query parameters)를 사용해서 필요한 데이터를 전달하거나 URL 경로의 특정 부분에 /{id}와 같이 변수를 넣어서 사용한다. 그렇다면 과연 GET 요청에 Request Body를 포함해서 요청을 보낼 수 있을까? 결론부터 얘기하면 HTTP 표준은 GET요청에 Request Body(요청 본문)를 포함할 수 있도록 허용한다. 하지만 GET 요청은 서버로부터 정보를 요청하고 응답을 받는 것에 중점을 두기 때문에, 요청 본문에 데이터를 담는 것은 권장되지 않는 방법이라고 한다. GET 요청에 Request Body를 넣는 것이 권장되지 않는 이유는 다음과 같다. 캐싱 : GET 요청은 캐..

개발 일지/CS 2023.06.22

DIP에 나오는 저수준 모듈 / 고수준 모듈의 의미

자바를 통해 개발 공부를 진행하고 있지만, 정작 가장 중요한 객체지향의 5대 원칙에 대해서 이해하고 프로젝트에 적용하고 있는가?라는 의문이 들었다. 그래서 객체지향 5대 원칙(SOLID)을 다시 공부하던 도중, 의존관계 역전 원칙에서 고수준 모듈과 저수준 모듈이 나오는데, 정확한 의미가 무엇인지 궁금하여 찾아보았다. 의존 역전 원칙 (Dependency Inversion Principle) - 고수준 모듈은 저수준 모듈의 구현에 의존해서는 안된다. 우선 저 말을 내가 이해하는 말로 다시 쓰면, '추상화에 의존해야지 구체화에 의존하면 안된다'라는 의미이다. 저수준 모듈은 고수준 모듈이 정의한 추상 타입에 의존해야 한다는 것이다. 고수준 모듈과 저수준 모듈이 뭔데..? 고/저는 무엇을 기준으로 나뉘는 거지...

개발 일지/Java 2023.06.12

토스 SLASH 23 개발자 컨퍼런스 후기

처음으로 개발자 컨퍼런스 라는 것을 경험해 봤다. 이번 컨퍼런스를 보면서 토스 개발자분들이 구현하는 것을 넘어서 최고의 사용자 경험을 위해서 고민하는 모습이 인상 깊었다. 아직 의욕만 앞서긴 하지만, 나름 프로젝트를 진행하면서 코드를 더 효율적으로 구현하고 실제 사용자가 서비스를 사용한다면 어떨까 라는 생각을 지속적으로 했던 나에게는 모니터에서 빛이 나지 않을 수가 없었다. (열심히 공부하겠읍니다..) 세션은 A, B로 나눠서 같은 시간대에 진행됐고 A 세션은 Frontend, DevOps, Core Banking에 관련된 내용들이 구성되어 있었고 B 세션은 Server와 관련된 내용들로 구성되어 있었다. 컨퍼런스는 이틀 동안 진행되고 내일도 마찬가지로 세션 A와 B로 나뉘지만 내용이 iOS, Andro..