백엔드
-
Spring 트랜잭션은 언제 어떻게 롤백 될까? -1편
개요스프링에서 @Transactional 어노테이션을 사용하면 트랜잭션이 자동으로 관리된다. 로직이 성공적으로 처리되면 commit을 통해 데이터베이스에 변경 사항이 반영되고, 오류가 발생하면 rollback을 통해 모든 변경 사항이 취소된다. 다만 이는 기본적인 개념으로 이번 글에서는 더 나아가 세부적으로 롤백이 정확히 언제 발생하고(1편), 특정 상황을 예시로 해당 로직이 롤백이 될지 안 될지에 대해 맞춰보는 식(2편)으로 알아보고자 한다. Check Exception, Unchecked Exception먼저 자바에서는 예외를 크게 다음과 같이 Exception과 Error 두 가지로 나누고 있다.Exception은 입력 값에 대한 처리가 불가능하거나 프로그램 실행 중에 참조된 값이 잘못된 경우인 ..
2024.10.04
-
[gradle] implementation, api 차이
개요Gradle에서 의존성을 설정할 때는 compileOnly, runtimeOnly, implementation, api 등 여러 가지 옵션을 사용할 수 있다. 특히 api와 implementation은 외부 라이브러리를 프로젝트에 추가할 때 가장 자주 사용하는 두 가지 방법으로, 이 둘은 모두 라이브러리를 추가하는 기능을 제공하지만 각기 다른 방식으로 동작하기 때문에 차이점을 알아두면 좋다.dependencies { api 'org.apache.httpcomponents:httpclient:4.5.7' implementation 'org.apache.commons:commons-lang3:3.5'}참고로 이전 Gradle 버전에서는 implementation 키워드가 없었고, 대신 comp..
2024.09.07
-
Spring Boot에서 여러 Kafka 클러스터 사용하기
개요프로젝트에서 일반적으로 하나의 Kafka 클러스터만을 사용하는 경우가 대부분이지만, 경우에 따라 서로 다른 환경의 Kafka 클러스터에 동시에 연결해야 할 필요가 생길 수 있다.나는 이번에 작업하면서 기존의 연결된 Kafka 클러스터 말고도 또 하나의 새로운 클러스터를 연결해야 했는데, 작업을 진행하면서 얻었던 지식을 공유하고자 작성하게 되었다. 컨슈머 설정Spring Boot는 기본적으로 ConcurrentKafkaListenerContainerFactory를 자동으로 구성하여 Kafka 리스너 컨테이너를 생성한다. 그러나 여러 Kafka 클러스터에 연결하려면 각 클러스터에 대해 별도의 ConcurrentKafkaListenerContainerFactory 빈을 생성하고, 해당 클러스터에 맞는 C..
2024.08.17
-
[JPA] deleteAll(), deleteAllInBatch(), deleteInBatch() 정리
개요Hibernate(JPA)에서는 레코드를 삭제할 수 있는 아래의 다양한 메서드들을 지원한다.delete(),deleteById()deleteAll(), deleteAllById()deleteInBatch()deleteAllInBatch(), deleteAllByIdInBatch()다양한 메서드를 제공하는 것은 좋지만, 네이밍만 보고 혼란스러운 것들이 몇몇 있다. 대표적으로 deleteInBatch()와 deleteAllInBatch(), 그리고 deleteAll()과 deleteAllInBatch()와 같은 메서드들이다.이번 게시글에서는 위 메서드들이 실제로 어떻게 삭제를 처리하는지를 살펴볼 것이고, 연관관계가 없는 경우와 연관관계가 있는 경우로 나누어 삭제 동작을 분석해 볼 것이다. 사전 세팅DB..
2024.08.12
-
단방향 @OneToMany의 문제점
개요JPA를 학습하다 보면 @OneToMany를 사용할 때 단방향보다는 양방향 매핑을 사용하라는 말을 자주 듣게 된다.왜 그런지 이해하기 위해 단방향 @OneToMany를 사용하는 두 가지 방법을 사용하여 문제점에 대해 살펴보고, 양방향을 사용했을 때 어떤 점이 개선되는지 알아보자매핑 테이블을 사용한 단방향 @OneToMany 동작 과정@JoinColumn 사용한 단방향 @OneToMany 동작 과정양방향 @OneToMany를 사용했을 때의 동작 과정 1. 매핑 테이블 사용매핑 테이블을 이용한 @OneToMany 엔티티 설계 예시는 다음과 같다.@Entity@NoArgsConstructor(access = lombok.AccessLevel.PROTECTED)public class Book { @I..
2024.07.26
-
@TransactionalEventListener 사용 시 주의점
문제 상황@Service@RequiredArgsConstructorpublic class CurrentValueChangeService { private final ExampleRepository exampleRepository; private final ApplicationEventPublisher applicationEventPublisher; @Transactional public void changeValue(String value) { Example example = exampleRepository.find(1L); String beforeValue = example.getCurrentValue(); example.updateCurren..
2024.07.03
-
도메인 엔티티와 영속성 엔티티
개요소프트웨어 아키텍처에서 도메인 엔티티와 영속성 엔티티를 분리하는 것은 중요한 설계 원칙 중 하나이다. 이 원칙은 클린 아키텍처의 핵심 개념을 기반으로 하며, 도메인 로직과 영속성 계층 간의 의존성을 최소화하여 시스템의 유지 보수성과 확장성을 높이는 데 목적이 있다.이번 게시글에서는 이러한 도메인 엔티티와 영속성 엔티티의 차이점에 대해 알아보고, 이 둘을 분리함으로써 얻을 수 있는 이점과 주의해야 할 점 그리고 언제 분리하면 좋을지에 대해 정리했다. 도메인 엔티티먼저 도메인 엔티티의 개념부터 살펴보면 도메인 엔티티는 비즈니스 도메인 내의 개념을 나타내는 객체로, 전자상거래 시스템에서는 'Order', 'Customer', 'Product'등이 도메인 엔티티가 될 수 있다. 다음은 간단한 예시 코드이다..
2024.06.18
-
협업을 위해 Swagger 좀 더 잘 사용해보기
목차API 그룹화API 버전 관리 시 @Deprecated 활용하기명세만 먼저 전달하기Authorize에 jwt 넣을 때 prefix에 Bearer 생략시키기브라우저 새로고침 후에도 인증정보 유지시키기기타 자잘한 상세 설정들 1. API 그룹화Swagger에서 API를 그룹화하면 여러 엔드포인트를 논리적인 그룹으로 묶어 관리하고 문서를 체계적으로 정리할 수 있습니다.설정 후에는 위 이미지처럼 관련된 엔드포인트만 볼 수 있어 원하는 API를 쉽게 찾고 관리할 수 있습니다. Swagger에서 API를 그룹화하는 방법은 어떤 라이브러리를 사용하고 있느냐에 따라 다르기 때문에 확인해서 적용하면 됩니다.springfox-swagger2를 사용하는 경우@Configuration@EnableSwagger2publi..
2024.05.15
-
AWS VPC를 사용한다면 알아야 할 네트워크 기초 지식
개요AWS를 사용하거나 다른 인프라 구조를 많이 살펴보다 보면 VPC(Virtual Private Cloud) 구조를 자주 접하게 됩니다. 이러한 VPC 구조를 이해하기 위해서는 네트워크 기초 지식이 꽤 많이 필요한데요, 이번 게시글에서는 AWS를 사용할 때 VPC의 개념과 관련 용어들에 대해 자세히 한번 살펴보도록 하겠습니다. 이번 게시글을 완독하고 나면 아래 이미지와 같은 구조를 이해할 수 있습니다. Amazon VPC(Virtual Private Cloud)란 무엇일까?Amazon VPC는 사용자가 정의하는 AWS 계정 전용의 가상 네트워크입니다. 사용자는 VPC 내에서 IP 주소 범위 선택, 서브넷 생성, 라우팅 테이블 및 네트워크 게이트웨이 구성 등 가상 네트워크 환경을 직접 구성할..
2024.04.24
-
select .. for update 대상 유무에 따른 잠금 상태
개요 InnoDB 엔진은 기본적으로 DDL 쿼리를 제외한 모든 데이터 조작 작업에서 테이블 락을 사용하지 않고 레코드 기반의 잠금 방식을 사용합니다. 더 자세히는 레코드 자체보다는 인덱스에 잠금을 설정하여 이루어지며, 테이블에 명시적인 인덱스가 없는 경우에도 내부적으로 생성된 클러스터 인덱스를 통해 잠금이 이루어집니다. 그리고 Repetable-Read 격리 수준에서 InnoDB는 record lock과 gap lock을 결합한 Next-key lock을 활용하여 Phantom Read를 방지합니다. 조건에 부합하는 특정 행을 찾기 위해 인덱스를 스캔하는 과정에서, InnoDB는 해당 인덱스 레코드뿐만 아니라 그 이전 공간에도 잠금을 설정합니다. 따라서 첫 번째 발견된 레코드와 쿼리가 정의한 범위 내의 ..
2024.04.11
-
Datadog 서버 모니터링 살펴보기
이미지를 클릭하면 큰 화면에서 더욱 자세하게 확인할 수 있습니다. Logs 먼저 가장 기본적인 로그 확인입니다. 좌측 메뉴에서 Logs를 선택하면 Datadog과 연동된 모든 서비스의 로그를 한눈에 볼 수 있습니다. 여기서 원하는 특정 서비스를 선택하여 그 서비스의 로그만을 상세하게 조회할 수도 있습니다. 로그 항목을 클릭하면 해당 로그에 대한 더 자세한 정보를 확인할 수 있습니다. 이때 Trace와 Metrics 기능이 매우 유용한데, 로그가 생성되기까지의 경로와 로그 발생 시점의 CPU 사용량, 메모리 사용량, 디스크 I/O 등의 중요한 메트릭을 상세하게 파악할 수 있습니다(Trace와 Metrics 화면은 아래에서 나올 화면과 동일하기에 아래에서 살펴보겠습니다). APM APM(Application..
2024.04.01
-
아키텍처 관점에서 늘어나는 트래픽 대응하기
개요아키텍처의 관점에서 늘어나는 트래픽을 어떻게 대응하면 좋을지에 대해 흐름에 따라 작성했습니다. 피드백은 언제든 환영이며 댓글 남겨주시면 감사하겠습니다. 한대의 인스턴스먼저 가장 간단한 구성입니다. 모든 트래픽이 한 대의 서버를 통해 관리되고 있습니다. 그리고 EC2의 IP가 유동적으로 변경되는 것을 방지하기 위해 Elastic IP를 연결시켜 놓았습니다.그러나 시간이 지나면서 사용자 수가 증가하고, 이에 따라 서버로의 트래픽도 늘어나기 시작했습니다. 이로 인해 EC2 인스턴스의 CPU 사용률이 증가하여 단일 EC2 인스턴스로는 증가하는 트래픽을 처리하는데 한계가 생기기 시작했습니다. 이 시점에서 고려할 수 있는 가장 기본적인 해결 방안은 EC2의 인스턴스 사양을 업그레이드하는 Scale-..
2024.03.24
-
내가 쓰는 IntelliJ 유용한 기능들
1. Global Data Sources 인텔리제이를 사용할 때, 각 프로젝트마다 데이터베이스(DB) 연결을 설정해 인텔리제이 내에서 직접 관리할 수 있습니다. 만약 모든 프로젝트에 걸쳐 공통적으로 사용하고 싶은 DB 연결이 있다면, 해당 연결을 Make Global로 설정함으로써 다른 프로젝트를 열어도 해당 DB 연결 설정을 유지할 수 있습니다. 2. Shelve 작업 중인 브렌치에서 다른 브랜치로 전환할 필요가 있을 때, 일반적으로는 git stash를 사용해 변경 사항을 임시로 저장한 후 이동합니다. 하지만 인텔리제이를 사용한다면 이와 유사한 기능인 Shelve를 통해 커밋하지 않은 코드를 임시로 저장할 수 있습니다. 이 기능을 통해 현재의 변경 사항을 인텔리제이 내부에 보관하고, 필요할 때 언제든..
2024.03.20
-
ThreadPoolExecutor 동작에 관한 오해
개요 Java에서 스레드풀을 효과적으로 관리할 수 있게 해주는 ThreadPoolExecutor, 그리고 이를 더욱 쉽게 사용할 수 있도록 Spring에서 제공하는 ThreadPoolTaskExecutor의 동작 방식에 관해 제가 그동안 잘못 이해하고 있었던 두 가지의 오해를 정리하고자 글을 작성하게 되었습니다. 내용은 다음과 같습니다. 별도의 설정을 하지 않으면 서버 실행 시에 지정한 스레드 풀 크기만큼 스레드가 자동으로 생성되지 않는다. corePoolSize와 maxPoolSize는 서로 상관없다. 큐의 크기를 지정해주지 않으면 maxPoolSize은 사실상 의미 없는 설정이다. corePoolSize크기 이상의 요청이 들어온다고 해서 maxPoolSize만큼 스레드를 생성하지 않는다. https:..
2024.03.11
-
[Kafka] 컨슈머 오프셋 수동으로 커밋하기
개요메시지 손실을 방지하기 위해 메시지 처리가 문제없이 완료되었을 경우에만 commit을 수행하도록, 컨슈머의 offset commit을 수동으로 설정하는 경우가 여러 존재합니다. 하지만 단순히 auto.offset.commit만 false로 지정하는 경우에는 원하는 방향으로 동작하지 않을 수도 있습니다.이번 게시글에서는 자동 커밋의 동작 과정과 주의점, 그리고 커밋을 수동으로 제어하기 위한 auto.offset.commit 설정과 ack-mode 설정에 대해 알아보겠습니다. auto.offset.commitKafka의 컨슈머는 읽은 메시지의 위치를 추적하기 위해 offset을 commit 하는 역할을 담당합니다. 이 offset은 Kafka의 내부 토픽인 __consumer_offsets에 저장되며,..
2024.03.06
-
외부 API를 연동할 때 고려하면 좋은 점들
개요 최근 프로젝트에서 외부 API를 연동하는 일이 굉장히 많았었는데, 작업하면서 얻은 다양한 경험과 지식을 공유하고자 작성하게 되었습니다. 피드백은 언제든 환영이며 댓글 남겨주시면 감사하겠습니다. 1. I/O와 트랜잭션을 분리해라 트랜잭션은 데이터베이스와 통신하기 위해 커넥션을 필요로 한다. 하지만 이 커넥션을 생성하는 데는 꽤 많은 비용이 들며, 대부분 이를 절약하기 위해 웹 애플리케이션 서버(WAS)는 실행 시 미리 일정 수의 커넥션 객체를 만들어 풀에 저장한다. 그리고 클라이언트의 요청이 발생하면 이 풀에서 이미 생성되어 있는 커넥션 객체를 사용하는 방식을 이용한다. 그러나 커넥션 풀의 크기는 제한되어 있기 때문에, 동시에 수많은 요청들이 커넥션 풀의 개수 이상으로 오게 된다면, 커넥션을 획득하지..
2024.02.24
-
[Kafka] 프로듀서 멱등성 보장하기
개요멱등성은 동일한 작업을 여러 번 수행하더라도 동일한 결과가 나타나는 특성을 의미합니다. 따라서 멱등성을 지닌 프로듀서는 같은 데이터를 여러 번 전송하더라도 해당 데이터가 카프카 클러스터에 단 한 번만 저장되도록 보장합니다.그렇다면 프로듀서에 어떻게 멱등성을 적용하고, 이를 통해 데이터의 중복 저장 없이 정확히 한 번만 저장되도록 보장할 수 있을까요? 이번 글에서는 프로듀서에 멱등성을 보장하도록 적용하는 방법에 대해 상세하게 알아보도록 하겠습니다. 메시지 전송 방식Producer와 Broker의 설정 및 구성에 따라 Kafka에서는 메시지 전달 보장 수준을 아래와 같이 세 가지 방식으로 구분합니다. 최대 한 번 (At most once): 메시지가 한 번만 전송되며, 재전송은 발생하지 않는다. 그러나..
2024.02.01
-
MySQL 버전에 따른 @Transactional(readOnly=true)의 동작 과정
개요 이 글은 태현님의 블로그 게시글에서 영감을 받아 작성하게 되었습니다. 우리는 스프링 프레임워크를 통해 RDBMS를 활용하는 과정에서, 우리는 성능 최적화, 가독성 향상, 데이터 일관성 유지 등 여러 이유로 비즈니스 로직에 @Transactional(readOnly=true) 어노테이션을 자주 사용하곤 합니다. 그런데 이 어노테이션은 어떠한 원리로 동작하는 것일까요? 이번 글에서는 @Transactional(readOnly=true)의 JDBC 단계에서의 동작 과정을 위주로 살펴보려 합니다. 동작 과정 비즈니스 로직에 @Transactional(readOnly=true)을 걸고 실행하는 경우 동작하는 전체적인 과정은 아래와 같습니다. 트랜잭션 시작 데이터베이스 연결 준비 읽기 전용 상태 전파 비즈니스..
2024.01.24
-
[랭킹 알고리즘] - Hacker News Algorithm
개요 공개된 Ranking Algorithm에는 가장 인기 있는 게시글을 선별하거나, 추천수를 바탕으로 순위를 매기는 알고리즘, 평점에 따라 순위를 결정하는 알고리즘 등 다양한 방식의 랭킹 알고리즘이 존재합니다. 이 중에서도 Hacker News Ranking Algorithm, Reddit Ranking Algorithm, 그리고 Highly Rated가 대표적인데, 이번 글에서는 이들 중에서도 조회수를 바탕으로 간편하게 적용할 수 있는 Hacker News Algorithm에 대해 자세히 알아보도록 하겠습니다. Hacker News Algorithm이란? Hacker News Algorithm은 Y Combinator가 운영하는 뉴스 공유 사이트인 Hacker News에서 사용하는 랭킹 알고리즘입니다..
2024.01.16
-
[Kafka] 리밸런싱 종류와 파티션 할당 전략
개요카프카 컨슈머는 토픽의 각 파티션에서 메시지를 처리하는 역할을 합니다. 그런데 특정 컨슈머가 문제를 겪게 되면 그 컨슈머가 처리하던 파티션의 소유권을 다른 컨슈머로 넘겨야 합니다. 이런 과정을 '리밸런싱'이라고 부르며 주로 아래 네 가지 상황에서 발생합니다.컨슈머 그룹에 새로운 컨슈머가 추가될 때기존 컨슈머가 그룹에서 나갈 때구독하는 토픽에 새로운 파티션이 생길 때컨슈머가 구독하는 토픽이 변경될 때리밸런싱이 가장 많이 일어나는 일반적인 상황은 애플리케이션 배포 시입니다. 기존 애플리케이션 종료 후 새로운 애플리케이션이 실행되면서, 기존 컨슈머가 삭제되고 새로운 컨슈머가 생성되기 때문입니다. 이 과정에서 리밸런싱이 최소 두 번 이상 발생하게 됩니다.그리고 리밸런싱 과정은 아래와 같은 문제점을 동반합니다..
2024.01.07
-
기업 정보를 수집하는 방법
공공 API 조사먼저 다른 채용 플랫폼들은 어떤 방법으로 기업 정보를 수집하고 있는지 조사를 시작했습니다. 대부분의 플랫폼들이 데이터의 출처를 명시해 놓아 조사하기는 수월했는데, 약 6개의 플랫폼을 살펴본 결과 대표적으로 나이스(NICE), 금융감독원(FSS), 금융위원회(FSC), 그리고 국민연금공단(NPS) 등에서 데이터를 제공받고 있는 것을 확인할 수 있었습니다. 그리고 더 나아가 중소벤처 24, 알리오, 클린아이 등에서도 데이터를 얻을 수 있는 것을 확인했습니다.각 데이터 출처의 웹사이트는 다음과 같습니다.나이스(NICE): https://www.niceinfo.co.kr/main.nice금융감독원(FSS): https://opendart.fss.or.kr/guide/main.do?apiGrpCd..
2023.12.28
-
Hibernate의 @Formula를 이용한 연관 관계 엔티티 집계
개요 Hibernate의 @Formula 어노테이션은 엔티티 클래스 내에서 실제로 데이터베이스 스키마에 존재하지 않는 '가상 컬럼'을 정의할 수 있는 기능입니다. @Formula를 사용하면 다른 컬럼들의 값에 기반하여 계산된 값을 표현할 수 있으며, 이 값은 엔티티를 조회할 때만 계산되어 사용됩니다. 예시 코드 @Formula 어노테이션의 전형적인 사용 사례는 연관된 데이터의 집계를 수행하는 경우입니다. 예를 들어, 게시글과 연결된 댓글의 수를 계산하는 경우를 들 수 있습니다. 아래는 간단한 예시 코드입니다. 전체 코드는 깃허브에서 확인 가능합니다. @Entity public class Post { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) pri..
2023.12.20
-
[Java] CompletableFuture로 비동기 및 병렬 처리하기
Future vs CompletableFuture Future와 CompletableFuture는 모두 Java에서 비동기 프로그래밍을 지원하기 위한 도구입니다. Java 5에서 도입된 Future는 비동기 연산의 결과를 표현하는 데 사용되며, Java 8에서 도입된 CompletableFuture는 Future를 확장하여 더 많은 기능을 제공합니다. CompletableFuture와 Future차이는 무엇일까요? Future에 대한 상세한 내용은 이번 포스팅의 주제에서 벗어날 것 같아 간단하게 CompletableFuture와의 차이점만 비교해 보았습니다. Blocking vs Non-Blocking Future는 get() 메서드를 통해 비동기 연산의 결과를 얻습니다. 하지만 이 메서드는 연산이 완료..
2023.12.12
-
Bucket4j로 트래픽 제한하기(Redis & MariaDB)
개요 최근 업무 프로젝트에서 특정(요금이 부가되는) 로직에 대해 월별 사용량을 제한하는 기능이 추가되어야 했습니다. 이와 관련하여 처리율 제한 기술을 알아보았는데 Bucket4j, Guava, RateLimitj, Resilience4j 등 다양한 라이브러리가 있는 걸 알게 되었고, 프로젝트 환경인 Spring Boot 2.7.x, MariaDB(nosql & in-momory부재), Java 11에 알맞은 Bucket4j를 선택하게 되었습니다. 다음은 고려한 라이브러리들의 특징과 그 선택 이유입니다. Guava: 다양한 핵심 Java 라이브러리를 제공하지만, 단순히 Rate Limiting 기능만을 위해 사용하기에는 다소 무거운 느낌이다. Resilience4j: 서킷 브레이커를 제공하는 라이브러리로 ..
2023.12.03
-
ShedLock으로 다중 인스턴스 환경에서 단일 스케줄러 동작 보장하기
개요 스프링에서 제공하는 @EnableScheduling 어노테이션은 간편하게 스케줄링 작업을 설정할 수 있게 해 주지만, 다중 인스턴스 환경에서는 동일한 작업이 여러 번 실행될 수 있다는 문제가 존재합니다. 이 문제를 해결하기 위해선 다양한 방법이 있지만, ShedLock이라는 오픈소스 라이브러리를 사용하면 손쉽게 해결할 수 있습니다. ShedLock은 스프링 스케줄링과 함께 사용될 수 있으며, 여러 인스턴스가 동일한 스케줄링 작업을 동시에 실행하는 것을 방지해 줍니다. 테스트 코드는 깃허브에서 확인하실 수 있습니다. ShedLock 이해하기 ShedLock은 분산된 시스템 환경에서 동일한 스케줄링 작업이 중복으로 수행되는 것을 방지하는 라이브러리입니다. 이 라이브러리는 지정된 작업에 잠금 메커니즘을 ..
2023.11.24
-
default method로 JpaRepository 좀 더 우아하게 써보기
개요 Spring Data JPA에서 JpaRepository 인터페이스를 사용할 때 Java 8에서 도입된 default method를 활용하면 기존 코드를 좀 더 깔끔하고 효율적으로 사용할 수 있다. Optional 제거하기 Spring Data JPA의 findByXX 메서드는 기본적으로 Optional을 반환한다. 이로 인해 비즈니스 로직에서 Optional 처리를 위한 추가적인 작업이 필요하게 되는데, 이럴 때 default 메서드를 활용하면 이 문제를 우아하게 해결할 수 있다. public interface UserRepository extends JpaRepository { // Default 메소드를 사용하여 findById의 Optional을 내부적으로 처리 default User fin..
2023.11.16
-
[Docker MySQL] Proxy Layer 구축하기
개요 이전 게시글 [Docker MySQL] Orchestrator를 이용한 High Availability(HA) 구축하기에서 마스터 서버에 장애가 발생했을 때 슬레이브 서버를 마스터 서버로 승격시키는 과정을 자동화하는 Orchestrator를 활용한 고가용성(High Availability, HA) 구성에 대해 살펴보았습니다. 이를 통해 마스터 서버의 모든 데이터 변경 사항이 자동으로 슬레이브 서버에 동기화되게 되며, 이를 통해 데이터의 일관성을 유지하고 마스터 서버의 부하를 효율적으로 분산시킬 수 있었습니다. 하지만, HA 구성만으로는 애플리케이션과 DB 서버 사이의 동기화 문제를 해결할 수 없습니다. 예를 들어, 애플리케이션의 설정 정보에는 장애가 발생한 db001이 마스터 DB로 설정되어 있다면..
2023.11.12
-
@Scheduled 사용할 때 스레드 설정
개요 스프링 프레임워크에서 제공하는 @Scheduled 어노테이션은 메서드에 스케줄링 기능을 부여하는 데 사용됩니다. 기본적으로 @Scheduled 어노테이션만을 사용하면 스프링은 단일 스레드에서 스케줄링 작업들을 순차적으로 처리하는데, 이는 하나의 스케줄링 작업이 완료되어야만 다음 스케줄링 작업이 실행될 수 있다는 것을 의미합니다. 따라서 부가적인 설정 없이 여러 개의 스케줄러를 작성하면, 일부 작업이 예상치 못한 시간에 동작할 수 있습니다. 예시 상황을 한번 보겠습니다. @Configuration @EnableScheduling public class ScheduledTasks { private final Logger log = LoggerFactory.getLogger(ScheduledTasks.c..
2023.11.09
-
[Docker MySQL] Orchestrator를 이용한 High Availability(HA) 구축하기
개요 이전 게시글 [Docker MySQL] Master-Slave Replication(복제) 구축하기에서 MySQL의 Master-Slave 복제 구성 방법에 대해 살펴보았습니다. 이를 통해 마스터 서버의 모든 데이터 변경 사항이 자동으로 슬레이브 서버에 동기화되게 되며, 이를 통해 데이터의 일관성을 유지하고 마스터 서버의 부하를 효율적으로 분산시킬 수 있습니다. 하지만, 마스터 서버에 문제가 발생하여 중단되면, 슬레이브 서버가 있음에도 불구하고 운영자가 직접 조치를 취하기 전까지는 슬레이브 서버를 마스터 서버로 대체하여 사용하는 것이 불가능하다는 문제가 또한 존재했었습니다. 이번 게시글에서는 이러한 문제를 해결하기 위해 마스터 서버에 장애가 발생했을 때 슬레이브 서버를 마스터 서버로 승격시키는 과정..
2023.11.06
-
[Docker MySQL] Master-Slave Replication(복제) 구축하기
개요MySQL의 Master-Slave Replication은 데이터 일관성(Consistency) 및 가용성(Availability)을 보장하기 위해 널리 쓰이는 기술입니다. 이 글에서는 Docker라는 컨테이너 도구를 활용하여 MySQL 환경에서 Master-Slave Replication을 구현하는 방법을 설명하려고 합니다. 이 과정은 크게 두 부분으로 나누어 설명하겠습니다.Master-Slave Replication 구성하기Bridge Network을 이용한 Replication 구성 Replication 동작 원리MySQL의 복제 기능은 클라이언트의 데이터 변경사항을 마스터 서버에서 슬레이브 서버로 복사하는 방식으로 작동합니다. 이 과정은 크게 4단계로 이루어집니다.변경사항의 기록: 클라이언트가..
2023.11.01
-
ArchUnit으로 아키텍처 검사하기
개요 ArchUnit은 Java 코드의 아키텍처를 검사하기 위한 간결하고 확장 가능한 오픈소스 라이브러리입니다. ArchUnit은 Java의 기본 단위 테스트 프레임워크를 활용하여, 주어진 Java 바이트 코드를 분석하고 모든 클래스의 구조를 해석함으로써 애플리케이션의 아키텍처를 체계적으로 테스트할 수 있게 해 줍니다. 패키지 및 클래스 의존성 검사: 패키지와 클래스 간의 의존 관계를 분석하고, 격리된 구조를 유지하는지 확인 상속 관계 및 순환 참조 검사: 클래스 간의 상속 구조를 분석하고, 순환 참조가 없는지 검사 레이어 아키텍처 검사: 레이어 간의 의존성을 검사하여, 명확하고 견고한 레이어 구조를 유지하는지 확인 코딩 컨벤션 검사: 사용자가 정의한 코딩 규칙을 검사하여, 일관된 코딩 스타일을 유지하는..
2023.10.28
-
504 Gateway TimeOut시 호출된 로직은?
개요 최근 작업을 하면서 504 Gateway TimeOut이 발생했고, 이에 따라 처음에는 서버 로직이 중단되었을 것이라 생각했으나 실제로는 그렇지 않았다. 어찌 보면 504는 서버(자세히는 WAS)에서 뱉은 오류가 아니기 때문에 당연한 말이지만 무심코 5xx 에러라 요청된 서버 로직도 중단될 줄 알았다. 그래서 504 Gateway TimeOut에 대해 다시 알아볼 겸 정리하게 되었다. 게이트웨이란 무엇인가? 게이트웨이는 통신 분야에서 서로 다른 네트워크를 연결을 하는 중개자 역할을 한다. 이를 통해 다른 통신 프로토콜이나 데이터 형식을 가진 네트워크 간의 소통이 가능해진다. 아래는 Nginx를 사용한 Gateway 구성에 대한 설명이다. Nginx는 웹 서버로 널리 알려져 있지만, 리버스 프록시 또..
2023.10.26
-
LocalStack을 활용한 AWS S3 테스트 환경 구축하기
개요 이번 글에서는 이전 게시글 'TestContainer로 통합 테스트 환경 구축하기'의 연장선으로, LocalStack을 이용하여 AWS의 S3 테스트 환경 구축에 대해 알아보겠습니다. 관련 코드는 깃허브에서 확인하실 수 있습니다. LocalStack이란? LocalStack은 AWS의 다양한 서비스들을 로컬 개발 환경에서 모방하여 사용할 수 있게 해주는 오픈소스입니다. 이를 활용하면, AWS의 주요 서비스들을 실제 클라우드 환경이 아닌 로컬에서 시뮬레이션하며 개발 및 테스트를 할 수 있습니다. LocalStack은 AWS의 다양한 서비스, 특히 S3, Lambda, DynamoDB, API Gateway, Kinesis, SQS 등의 주요 서비스들을 지원하며, Docker 환경에서 실행되기 때문에 ..
2023.10.22
-
TestContainer로 통합 테스트 환경 구축하기
[개요]통합 테스트 환경을 구축할 때, 데이터베이스와의 연동은 주요한 고려사항 중 하나이며, 테스트의 안정성과 신뢰성을 높이기 위해서는 실제 운영 환경과 유사한 데이터베이스 환경에서의 테스트가 필요합니다. 그러나 이러한 환경을 갖추기 위해선 여러 방법이 있고, 각각의 방법은 그 특성과 장단점이 있습니다. 이번 게시글에서는 TestContainer를 이용한 테스트 환경 구축에 대해 알아보겠습니다.전체 코드는 깃허브에서 확인하실 수 있습니다. [DB를 테스트 환경에 통합하는 방법]Local에 실제 DB를 연결하기Local 환경에 직접 DB를 실행하는 방법은 실제 환경과 유사하게 테스트를 할 수 있는 큰 장점이 있습니다. 그러나 여러 테스트를 동시에 진행하거나 데이터를 관리하는 측면에서 멱등성(idempo..
2023.10.15
-
[MySQL] MVCC를 통한 잠금없는 읽기
[MVCC(Multi Version Concurrency Control)] MVCC는 여러 트랜잭션이 동시에 같은 데이터에 접근할 때, 데이터의 일관성과 동시성을 보장하는 방식입니다. 이 기술의 핵심은 잠금(Locking) 없이 데이터를 일관되게 읽는 것이며, InnoDB 스토리지 엔진은 이를 구현하기 위해 언두 로그(Undo log)를 활용합니다. '멀티 버전'은 동시에 여러 버전의 데이터를 관리한다는 개념을 나타냅니다. 예를 들어, 다음과 같은 'member' 테이블을 생성하고 레코드를 추가하였다고 가정해 봅시다. CREATE TABLE member ( m_id INT NOT NULL, m_name VARCHAR(20) NOT NULL, m_area VARCHAR(100) NOT NULL, PRIMA..
2023.10.07
-
[MySQL] 사용자 생성 및 권한 부여 방법
[개요] MySQL은 사용자 계정의 관리 방식이 다른 DBMS와 약간 차이가 있습니다 많은 DBMS에서는 아이디로 사용자를 식별하지만, MySQL은 사용자 아이디 외에도 접속하는 IP 주소를 함께 고려하여 더욱 정밀한 접근 제어를 제공합니다. 또한, MySQL 8.0 버전부터는 '역할(ROLE)'이라는 개념도 도입되었고, 이를 통해 미리 정의된 권한 그룹, 즉 'Role'을 사용자에게 쉽게 부여할 수 있게 되었습니다. [사용자 식별] 계정과 호스트명 대부분의 DBMS는 계정 이름만으로 사용자를 식별하지만, MySQL은 사용자의 계정과 접속 지점(클라이언트 호스트명, 도메인, IP 주소)을 동시에 고려합니다. 따라서 MySQL 계정을 언급할 때는 아래의 예처럼 아이디와 호스트 정보를 명시해야 합니다. 's..
2023.10.06
-
[JVM 매개변수] InitialRAMPercentage, MinRAMPercentage, MaxRAMPercentage
개요 Java 8부터, InitialRAMPercentage, MinRAMPercentage, 그리고 MaxRAMPercentage 세 가지 JVM 파라미터가 도입되어 사용자자가 Java 애플리케이션의 힙 크기를 더 유연하게 설정할 수 있게 되었습니다. 기본적으로 JVM은 물리적 메모리에 기반하여 메모리를 할당하지만, 컨테이너 환경이 발전하면서 JVM도 컨테이너의 메모리를 기준으로 메모리를 할당하게 개선되었습니다. InitialRAMPercentage -XX:InitialRAMPercentage 파라미터는 Java 애플리케이션의 초기 힙 크기를 설정하는 데 사용됩니다. 이 값은 서버나 컨테이너의 전체 메모리 백분율로 설정되며, double 값으로 전달됩니다. 예를 들어, 1GB 메모리를 갖는 서버에서 -..
2023.10.01
-
[GA] UTM으로 유입 경로 추적하기
개요오늘날의 비즈니스는 데이터로 의사결정을 한다는 말이 있을 만큼 데이터는 중요한 의사 결정 도구 중 하나입니다. 과거에는 TV, 라디오, 잡지 등 다양한 광고 매체를 통해 제품이나 서비스를 알렸으나 그 효과를 정확히 측정하는 것이 불가능했습니다. 그러나 현재에는 사용자의 온라인 활동, 웹사이트 방문, 제품 구매 등 모든 활동을 추적하는 것이 가능해졌습니다.구글 애널리틱스(GA)는 이러한 사용자의 온라인 활동을 분석하는 데 유용한 도구로, 특히 UTM 파라미터는 웹 사이트 트래픽의 유입 경로를 상세히 추적하는 데 매우 중요한 역할을 하고 있습니다. UTM 파라미터란?UTM 파라미터란 URL의 끝에 추가되는 코드로, 사용자가 웹 사이트를 어디서 방문하였는지에 대한 상세한 정보를 제공합니다. 다들 한 번쯤..
2023.09.22
-
MySQL에서 VARCHAR와 TEXT의 차이
개요 MySQL의 문자열데이터 타입 중 VARCHAR와 TEXT는 상당히 흔히 사용됩니다. 그동안 VARCHAR는 255byte만 지원했지만, MySQL 5.0.3 이후로 VARCHAR와 TEXT 타입 모두 최대 65,535byte 길이를 지원하게 되었습니다. VARCHAR와 TEXT는 둘 다 문자열을 저장하기 위한 데이터 타입이며, 둘의 주요 차이점과 특징은 다음과 같습니다. 저장 용량 VARCHAR의 저장 구조 VARCHAR는 최대 65,535byte까지 저장이 가능하며, '(현재 저장된 byte의 크기) + (길이를 표현하는 byte)'로 구성됩니다. 예를 들어 'apple'의 경우, 문자열 'apple'은 5byte이며, 그 길이를 표현하는 바이트는 1byte이므로 총 6byte가 필요합니다. 여..
2023.09.17
-
Redis의 데이터 타입, 명령어와 활용 사례
간단 요약 데이터 타입 명령어 설명 예제 Strings SET 값 저장 `$ SET key value` GET 값 조회 `$ GET key` Lists LPUSH 왼쪽부터 값 추가 `$ LPUSH mylist value` LPOP 왼쪽에서 값 제거 `$ LPOP mylist` LINDEX 특정 위치의 값 조회 `$ LINDEX mylist 0` Sets SADD 값 추가 `$ SADD myset value` SMEMBERS 모든 멤버 조회 `$ SMEMBERS myset` Sorted Sets(ZSets) ZADD 값 및 점수 추가 `$ ZADD myzset score member` ZRANK 특정 멤버의 순위 조회 `$ ZRANK myzset member` ZRANGE 점수 범위로 멤버 조회 `$ ZR..
2023.09.05
-
분산락으로 선착순 이벤트 구현하기
선착순 이벤트 요구사항선착순으로 n명까지만 기프티콘을 받을 수 있다.기프티콘은 1인당 한번, 즉 중복으로 받을 수는 없다.저는 분산락을 통해 동시성 이슈를 해결하고, 위 요구사항을 충족하기 위해 Redis를 활용하기로 했습니다. 그 이유는, Redis는 In-memory DB로써 속도가 빠르며, RDB에서 락을 사용하기 위해서는 별도의 커넥션 풀을 관리해야 하고, 락에 관련된 부하를 RDB에서 받는다는 점이 효율적이지 않다고 생각했기 때문입니다. 분산락을 선택한 이유Redis는 "싱글스레드로 명령을 수행하므로, 애초에 동시성이 발생할 수가 없는 거 아니야?"라고 생각할 수 있습니다.일단 질문에 대한 답은 맞습니다. Redis의 명령 자체는 원자적(atomic)입니다. 하지만 아래와 같이 여러 개의 연속..
2023.08.31
-
실무에서 Redisson을 연결하면서 겪은 문제점들
Redisson을 실무에 적용하면서 겼었던 연결 문제와 해결 방법을 한번 정리해보려고 한다. 첫 번째로, 다음과 같은 오류가 발생했다. Caused by: org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.redisson.api.RedissonClient]: Factory method 'redissonClient' threw exception; nested exception is org.redisson.client.RedisConnectionException: Unable to connect to Redis server: [Redis 주소] at org.springframework.beans.factory.su..
2023.08.18
-
Java에서 assert와 exception
서론 Java에서 개발자는 버그 또는 예상치 못한 상황을 검출하고 적절히 대응하기 위한 다양한 메커니즘을 사용할 수 있는데, 대표적으로 assert와 exception을 사용할 수 있습니다. 두 가지 기능은 비슷해 보이지만, 사용 목적, 적용 시나리오, 그리고 특성에서 중요한 차이점이 있습니다. Exception exception은 프로그램의 일반적인 실행 흐름에서 예상치 못한 상황이 발생했을 때, 이를 적절히 처리하기 위한 Java의 기본 메커니즘입니다. Java의 예외는 크게 두 가지로 구분됩니다. 1. Uncheked Exception(또는 RuntimeException) int x = 0; int y = 5 / x; // ArithmeticException 발생 실행 시간에 발견되는 예외로, Ru..
2023.08.11
-
Spring Data Redis의 @Indexed 사용 시 주의점
@Indexed란? @Indexed는 Spring Data Redis 모듈의 주요 어노테이션 중 하나입니다. 주 목적으로는 Redis의 보조 인덱스(Secondary Index) 생성에 사용되며, @Id가 붙여진 객체 외에도 @Indexed가 붙여진 객체로도 값을 조회할 수 있게 합니다. 예를 들어, 아래의 코드에서는 id뿐만 아니라 name으로도 데이터를 검색할 수 있습니다. @RedisHash("Person") public class Person { @Id private String id; @Indexed private String name; private int age; } 예시 한번 Person("dkswnkk", "JuHyeong", 26)을 저장한다고 가정해 보겠습니다. @Indexed 없이 ..
2023.08.07
-
WebClient에서 에러 처리와 재시도하는 방법
서론 HTTP 요청은 네트워크 지연, 일시적인 서버 오류, 잘못된 요청 등 다양한 이유로 실패할 수 있습니다. 이런 경우 애플리케이션의 실행 흐름에 문제를 일으킬 수 있기에 에러를 올바르게 처리해야 합니다. 이번 글에서는 WebClient를 사용시 HTTP요청 과정에서 발생한 에러를 처리하는 방법과 복구하기 위해 재시도 처리하는 전략에 대해 정리해 보겠습니다. 에러 처리 onErrorReturn() onErrorReturn()은 에러가 발생했을 때 주어진 default 값을 반환하는 메서드입니다. 이는 비동기 통신에서 중요한 역할을 하는데, 특히 네트워크 오류 또는 서버의 문제로 인한 에러가 발생했을 때 통신 자체를 중단시키지 않고, 디폴트 값을 반환하여 정상적으로 계속 작동할 수 있도록 할 수 있기 때..
2023.08.03
-
Spring Batch란? 간단한 개념과 코드 살펴보기
서론 스프링 배치(Spring Batch)는 대용량 데이터를 처리하기 위한 프레임워크로, 스프링 프레임워크 기반에서 작동합니다. 일반적으로 배치 작업은 대량의 데이터를 처리하거나, 주기적이고 반복적인 작업을 실행하는 데 사용되며, 스프링 배치는 이러한 작업을 효율적이고 안정적으로 처리할 수 있는 대표적으로 아래와 같은 기능들을 제공합니다. 로깅 및 추적 트랜잭션 관리 작업 처리 통계 작업 재시작 건너뛰기 리소스 관리 Batch와 Scheduler의 차이 배치(Batch)는 논리적 또는 물리적으로 관련된 일련의 데이터를 그룹화하여 일괄 처리하는 방법을 의미합니다. 반면에 스케줄러(Scheduler)는 주어진 작업을 미리 정의된 시간에 실행할 수 있게 해주는 도구나 소프트웨어를 의미합니다. 여기서 주의할 점..
2023.07.29
-
스프링에서 @Async를 사용할때 주의점
개요비동기 프로그래밍은 오늘날의 소프트웨어 개발에서 매우 중요한 개념입니다. 대용량 데이터 처리, 느린 I/O 작업, 복잡한 계산 등 다양한 작업을 병렬로 처리하면서 시스템의 응답 시간을 개선하고, 리소스를 효율적으로 사용하는데 도움이 되기 때문입니다.스프링에서는 @Async 어노테이션을 통해 이러한 비동기 메서드를 간단하게 실행할 수 있는데, 이러한 @Async 어노테이션을 사용할 때 주의해야 할 여러 가지 사항에 대해서 정리해 보겠습니다. 주의점Exception Handling메서드 호출리턴 타입트랜잭션 관리Execution Exception Handling기본적으로 @Async 메서드에서 발생하는 예외는 호출자에게 전파가 되지 않습니다. 이는 @Async 어노테이션이 붙은 메서드가 별도의 스레드..
2023.07.24
-
Kafka 개념과 Spring Boot + Kafka 간단한 연동
서론기존 데이터 시스템의 구조는 각 애플리케이션과 데이터베이스가 end-to-end로 직접 연결되어 있었습니다. 이러한 구조는 간단하지만 각각의 데이터 파이프라인이 분리되어 있어, 요구사항이 증가함에 따라 시스템의 복잡도를 높이는 결과를 가져왔고, 크게 아래와 같은 문제점들이 발생했습니다.시스템 복잡도의 증가중앙화된 데이터 전송 영역이 없어, 데이터의 흐름을 파악하기 어렵고, 시스템 관리가 복잡함.시스템의 일부분에 문제가 발생하면, 연결된 모든 애플리케이션들을 확인해야 함.데이터 일관성 유지의 어려움데이터가 여러 시스템과 데이터베이스에 분산되어 있는 경우, 한 시스템에서 변경된 데이터가 다른 시스템에 즉시 반영되지 않아 데이터의 일관성을 유지하기 어려움.데이터 실시간 처리의 어려움전통적인 메시지 큐 시스..
2023.07.19
-
스프링 이벤트 발행과 구독으로 트랜잭션 분리하기
서론서비스를 만들다 보면 다양한 외부 모듈이나 시스템을 연동해야 하는 상황이 생기게 됩니다. 대표적으로 다음과 같은 상황을 들 수 있습니다.코드로는 다음과 같습니다.@Service@Transactional(readOnly = true)@RequiredArgsConstructorpublic class UserService { private final MessageService messageService; private final UserRepository userRepository; @Transactional public void signUp(String email) { // 유저 저장 userRepository.save(new User(email)); ..
2023.07.09
-
SSE로 알림 기능 구현하기 with Spring
서론 인터넷은 웹 브라우저와 웹 서버 간의 데이터 통신을 위해서 HTTP 표준 위에 구축되어 있습니다. 대부분의 경우 웹 브라우저인 클라이언트가 HTTP 요청을 서버에 보내고, 서버는 적절한 응답을 반환하는데 이런 왕복 통신은 'https://www.google.com'과 같은 주소를 브라우저에 입력했을 때 웹 페이지를 받게 되는 과정입니다. 이러한 HTTP 표준은 광범위하게 지원되지만, 애플리케이션이 연속적인 정보를 서버에 전송하거나, 실시간으로 업데이트된 서버의 정보를 클라이언트에게 보내야 하는 경우 지속적인 HTTP 요청을 하게 되기에 비용면에서 매우 비 효율적입니다. 이런 상황에서 폴링, 웹소켓, 그리고 SSE가 등장했는데, 이들은 데이터 스트림의 속도와 메모리 효율성에 중점을 둔 프로토콜 들입니..
2023.06.18
-
Docker 컨테이너에 MariaDB 설치하기
서론매번 새로운 DB 컨테이너를 생성할 때마다 검색하면서 찾아보기도 번거롭고, 그렇다고 세팅 주기도 그렇게 짧지 않아 기억도 잘 되지 않아서 이번 기회에 아예 문서화를 하고자 작성하게 되었습니다.목차Docker 설치MariaDB Container 설치MariaDB 사용자 추가 및 user 권한 설정Dokcer의 다양한 명령어 Docker 설치먼저 Docker가 설치되어 있지 않다면 Docker를 설치해야 합니다. Docker의 설치는 https://www.docker.com/에서 가능합니다. Docker는 Docker Engine(Daemon)과 Docker CLI(Client)를 Docker라는 용어로 묶어서 사용하는데, 이들은 Docker에서 제공하는 서로 다른 두 가지 구성 요소입니다.Docker ..
2023.05.12
-
일급 컬렉션(First-Class Collection)이란?
일급 컬렉션(First-Class Collection)이란? Java에서 일급 컬렉션(First-Class Collection)은 다른 객체와 동등한 지위를 갖는 컬렉션 객체를 말합니다. 일급 컬렉션은 다음과 같은 특징을 가집니다. 컬렉션 객체는 변수나 매개변수에 할당할 수 있다. 컬렉션 객체는 다른 객체와 동등한 지위를 가진다. 컬렉션 객체는 반환값으로 사용할 수 있다. 컬렉션 객체는 필요한 경우 메서드에서 생성할 수 있다. 그냥 간단하게 한 문장으로 말하면 Collection을 Wrapping 하면서, 그 외 다른 멤버 변수가 없는 상태를 일급 컬렉션이라 합니다. 예시 코드 코드로 살펴보면 다음과 같습니다. 먼저 일급 컬렉션을 사용하지 않은 코드입니다. public class Student { pri..
2023.04.12
-
인덱스를 안타는 쿼리들
인덱스란? 인덱스(Index)는 데이터베이스에서 데이터 검색 속도를 향상하기 위한 자료구조입니다. 인덱스는 데이터베이스에서 데이터를 찾는 데 사용되며, 색인이라고도 합니다. 인덱스는 주로 WHERE 조건절에 사용되는 컬럼에 생성됩니다. 인덱스는 B-트리(B-tree)나 해시 테이블(hash table)로 구현할 수 있지만, 대부분의 DBMS에서는 다음과 같은 장점 때문에 B-트리를 인덱스 자료구조로 사용합니다. 항상 정렬된 상태로 특정 값보다 크고 작은 부등호 연산에 문제가 없다. 참조 포인터가 적어 방대한 데이터 양에도 빠른 메모리 접근이 가능하다. 데이터 탐색뿐 아니라, 저장, 수정, 삭제에도 항상 O(logN)의 시간 복잡도를 가진다. 보통 INDEX를 테이블의 특정 컬럼에 한 개 이상을 주면 In..
2023.03.23
-
Java의 기본 함수형 인터페이스
서론 사내 코드를 살펴보다가 함수형 인터페이스, 그중에서도 BiFunction을 사용한 로직을 자주 볼 수 있었는데, 실제로 보니 생소하기도 하고, 저도 로직에 한번 녹여보고 싶어서 이번 기회에 정리를 해보려고 합니다. 함수형 인터페이스 종류 Java의 함수형 인터페이스는 JAVA 8부터 도입된 기능으로, 하나의 추상 메서드만 가지는 인터페이스를 의미합니다. 이러한 인터페이스들은 람다 표현식이나 메서드 참조를 통해 간단하게 표현할 수 있으며, Java에서는 java.util.function 패키지를 통해 미리 정의된 다양한 함수형 인터페이스를 제공합니다. Java에서 미리 정의해 둔 주요 함수형 인터페이스는 다음과 같습니다. Function: 입력 인수 T를 받아 결과 R을 반환하는 함수를 나타낸다. 주..
2023.03.20
-
Java의 예외 생성 비용은 비싸다
서론 보통 프로젝트를 진행할 때, 아래와 같은 장점 때문에 자바에서 제공하는 예외 클래스 외에 개발자가 직접 Custom Exception 클래스를 정의하여 자주 사용합니다. 에러 처리의 일관성과 가독성 유지: 개발자가 직접 예의 클래스를 정의하므로, 에러 메시지를 보다 명확하게 정의할 수 있고, 개발자가 직접 일관성 있게 에러처리를 정의할 수 있다. 로깅 및 디버깅에 용이: 개발자가 예외 클래스에 디버깅 정보를 추가하여 예외가 발생했을 때 디버깅을 용이하게 할 수 있다. 예외 처리의 유연성: 예외 클래스를 상속하여 사용하는 등 다양한 예외 처리 방식을 적용할 수 있다. 하지만 이러한 장점 외에도, 자바에서는 Exception의 처리 비용이 매우 비싸다는 문제가 있습니다. 이번 게시글에서는 JVM에서 E..
2023.03.10
-
Gradle로 멀티모듈 프로젝트 구성하기
서론 현재 제가 있는 부서에서는 같은 데이터베이스를 공유하는 다수의 프로젝트가 존재하는데, 하나의 도메인을 공유하고 깃을 따로 관리하기 위해 도메인 클래스들은 멀티 프로젝트에 Nexus Maven 저장소를 이용해서 도메인 클래스를 분리하는 형태로 사용하고 있습니다. 저는 이미 세팅이 된 환경에서 개발을 하고 있기에 따로 설정에 관해서는 건드릴 부분이 없기도 하고, 직접 구성해 본 적도 없어서 이번기회에 정리와 함께 직접 환경 구성을 해보고자 포스팅하게 되었습니다. 이번 게시글에서는 멀티모듈의 정의와 Gradle을 이용한 멀티모듈의 구성에 대해 정리해보겠습니다. 목차 멀티모듈이란? Gradle로 멀티모듈 구성하기 테스트 테스트 환경 Apple Silicon (M1), IntelliJ Java 11, Spr..
2023.03.04
-
트랜잭션(Transaction)의 예외(Exception)에 따른 롤백 처리
서론이전에 Java의 Checked Exception과 UnChecked Exception에 대해 정리한 적이 있습니다. 다시 요약하면 RuntimeException을 상속하지 않는 클래스는 Checked Exception, 상속한 클래스는 Unchecked Exception이며, Checked Exception은 try-catch을 통해 예외를 꼭 처리해 주어야 컴파일에서 오류가 발생하지 않습니다.이번 포스팅에서는 이러한 각각의 예외들에 대하여 Transaction에서 롤백이 어떻게 반영되는지 한번 정리해 보겠습니다. 공통 코드@Entity@NoArgsConstructor(access = AccessLevel.PROTECTED)public class User { @Id @GeneratedVa..
2023.02.05
-
디미터 법칙 (Law of Demeter)이란?
최근 클린코드를 읽던 중 디미터 법칙에 대해 알게 되었습니다. 용어 자체는 생소하긴 한데 법칙의 내용 자체는 크게 어렵지 않고, 평상시 개발에서 흔히 마주칠 수 있는 내용을 다룬 법칙이기 때문에 한번 정리를 해보려고 합니다. 디미터 법칙이란? 디미터 법칙(Law of Demeter)은 데메테르 법칙이라고도 불리며 줄여서 LoD라고도 불립니다. 이 법칙은 "최소한의 지식 원칙(The Principle of Least Knowledge)으로 알려져 있으며, 모듈은 자신이 조작하는 객체의 속사정을 몰라야 한다는 것을 의미합니다. 실제로 Demeter라는 프로젝트를 진행하던 개발자들은 어떤 객체가 다른 객체에 대해 지나치게 많은 정보를 알고 있다 보니, 서로에 대한 결합도가 높아지고 이로 인해 좋지 못한 설계를..
2023.02.01
-
DB 커넥션 풀(Connection Pool)과 Hikari CP
서론 HikariCP는 데이터베이스와 애플리케이션 간의 연결을 관리하는 데 있어, 가장 빠르고 가벼운 Connection Pool 오픈소스 라이브러리 중 하나입니다. 이번 게시글에서는 Connection Pool과 Hikari CP에 대해 한번 정리해 보겠습니다. 목차 전통적인 WAS와 DB 연결 방법 Connection Pool이란? Connection Pool을 무작정 크게 만들면 성능이 좋아질까? 이상적인 Connection Pool의 크기는 얼마일까? Hikari CP란? 전통적인 WAS와 DB 연결 방법 일반적으로 웹 애플리케이션은 CRUD와 같은 데이터를 연산 작업을 처리할 때 위 이미지와 같이 DB에 직접 연결하기 위해 매번 드라이버(Driver)를 로드하고 connection 객체를 받아오..
2023.01.18
-
토큰(token)의 탈취를 최대한 예방하기
서론 먼저 간단하게 토큰에 대해 설명하면 토큰이란 서버가 각각의 클라이언트가 누구인지 구별할 수 있도록 사용자의 유니크한 정보를 담은 암호화된 데이터입니다. 사용자는 토큰 유효 기간 동안 동일한 웹페이지나 앱, 혹은 그 밖에 해당 토큰을 사용하는 리소스로 돌아갈 때마다 자격 증명을 다시 입력할 필요 없이 토큰이 발급된 웹사이트나 앱에 액세스 할 수 있습니다. 이렇듯 토큰은 토큰 자체에 사용자의 권한 정보나 서비스를 사용하기 위한 정보가 포함되어 있습니다. 여기서 Json 포맷을 이용하여 사용자에 대한 속성을 저장하는 Web Token을 JWT(Json Web Token)이라고 부르는데, 이번 포스팅에서는 이러한 JWT토큰의 탈취에 대처하는 방법에 대해서 정리해 보겠습니다. 목차 Access Token과 ..
2023.01.14
-
작업 임시 저장하기 IntelliJ의 Shelve
서론 특정 branch에서 작업을 하다가 다른 branch로 이동을 해야 하는 상황이 있습니다. 그럴 때 checkout을 통해 branch를 이동을 시도하면 위와 같이 commit 혹은 stash를 먼저 하라는 문구를 많이 보셨을 겁니다. 혹은 IntelliJ IDE를 통해 checkout를 시도했을 때는 위와 같은 창이 띄워지며 변경 내역을 먼저 처리하도록 유도합니다. 지금까지 저는 git stash를 통해 작업사항을 임시로 저장했으나 또 다른 방법인 IntelliJ의 Shelve라는 기능을 알게 되어 정리를 하게 되었습니다. IntelliJ Shelve 먼저 branch를 checkout 하기 전 IntelliJ 좌측의 Commit을 통해 변경사항을 저장할 파일들을 체크박스를 눌려 체크합니다. 그 ..
2023.01.13
-
Spring JDBC를 사용하여 Batch Insert 수행하기
서론 평소에 JPA를 활용하면서 데이터를 추가할 때, 많은 개발자들이 repository.save() 함수를 이용하여 단건 단위로 저장하는 로직을 구현합니다. 그러나 수백, 수천 개 이상의 대량 데이터를 저장해야 하는 경우에도 해당 방법을 사용해도 될까요? 이는 성능과 클라이언트의 대기 시간을 결정하는 중요한 요소입니다. 따라서 이번 글에서는 Spring 환경에서 다량의 데이터를 효율적으로 삽입하는 방법인 Batch Insert에 대해 알아보려 합니다. 테스트는 Apple Silicon (M1), Java 11, Spring Boot, JPA, JUnit5, Docker MySQL 환경에서 진행하였으며, 소스코드는 깃허브에서 확인 가능합니다. 목차는 다음과 같습니다. Batch Insert란? Ident..
2023.01.09
-
자바에서 동시성을 해결하는 다양한 방법과 Redis의 분산락
이번 포스팅은 사전지식으로 운영체제의 동기화 이론에 대해 알고 있어야 손쉽게 이해할 수 있으므로, 헷갈리시는 분들은 아래 포스팅을 먼저 읽고 이번 포스팅을 읽어주시면 감사하겠습니다. [OS] 프로세스 동기화(Process Synchronization) 서론 협력적 프로세스는 시스템 내에서 실행 중인 다른 프로세스의 실행에 영향을 주거나 영향을 받는 프로세스입니다. 협력적 프로세스는 논리 주소 공간(즉, 코드 및 데이터)을 직접 공유하거 dkswnkk.tistory.com 공유자원에 대해 동시에 여러 개의 프로세스가 접근하여 생기는 경쟁 상황(race condition)을 우리는 동시성 문제라고도 하며, 더 자세히는 동일한 하나의 데이터에 두 개 이상의 스레드, 혹은 세션에서 가변 데이터를 동시에 제어할 ..
2023.01.08
-
해시 자료구조와, 해시 충돌 그리고 Java의 HashMap 동작 방법
목차 해시란? 해시함수란? 해시 충돌 완화 방법 Java에서 HashMap 동작 방법 해시(Hash)란? 해시(Hash) 구조란, key-value쌍으로 이루어진 데이터 구조로써, 해시 구조에서는 key를 이용하여 value를 빠르게 찾을 수 있다는 장점이 있습니다. 파이썬의 Dicitionary, 루비의 Hash, Java의 HashMap, C++의 unordered_map이 해시 테이블의 대표적인 예입니다. 해시 함수(Hash Function)이란? 해시 함수란, 임의 길이의 입력 값을 고정 길이의 암호화된 출력으로 변환해주는 함수입니다. key를 해시 함수에 넣어서 나오는 결과가 hash이며, 결국 해시 함수란 key를 hash로 만들어내는 함수입니다. 해시 함수는 다음과 같은 크게 세 가지의 특징..
2022.12.30
-
[Java] Checked Exception과 UnChecked Exception
서론 최근에 자바에서 Checked Exception과 Unchecked Exception의 차이가 무엇이냐는 질문을 받았었는데, 전혀 몰랐어서 정리를 하게 되었습니다. 먼저 결론부터 말씀드리면 아래와 같습니다. "RuntimeException을 상속하지 않는 클래스는 Checked Exception, 상속한 클래스는 Unchecked Exception" 목차 Error와 Exception 차이 예외 클래스 계층 구조도 왜 RuntimeException을 상속하면 UnChecked Exception일까? Error와 Exception 차이 프로그램이 실행 중 어떤 원인에 의해서 오작동을 하거나 비정상적으로 종료되는 경우가 있습니다. 이러한 결과를 초래하는 원인을 프로그램 에러 또는 오류라고 합니다. 여기..
2022.12.18
-
가비아 + Linux + Nginx + Cerbot/SSL을 활용한 https 설정
서론 가비아 + Linux + Nginx + Cerbot/SSL을 활용한 https 설정에 대해 문서화하고자 글을 작성하게 되었습니다. 환경 웹 서버: Nginx 인증서 발급: Cerbot/SSL 운영체제: Amazone Linux 도메인 구매: 가비아 목차 도메인 구매 및 설정 Nginx 설치 및 수정 Cetbot 설치 및 SSL 발급 Proxy 설정 인증서 자동 갱신(선택) 1. 도메인 구매 먼저 도메인이 필요합니다. 도메인은 사람들이 원하는 사이트에 방문하기 위해 브라우저에서 입력하는 주소를 말합니다. https 적용에 있어서 도메인이 필요한 이유는 SSL 인증서를 발급받을 때 도메인이 아니라 IP일 경우에는 인증서 발급이 제한되기 때문입니다. 도메인을 얻을 수 있는 사이트는 굉장히 많지만 저는 그..
2022.12.05
-
Spring Boot + GitHub Actions + AWS CodeDeploy를 활용한 CI/CD 구축
서론 지금까지 매번 프로젝트를 구축할 때마다 이전 코드들을 번거롭게 봐가면서 CI/CD를 구축했었는데, 이번 기회에 한번 문서화를 해보고자 글을 작성하게 되었습니다. [CI/CD] CI/CD란?, 지속적 통합(Continuous Integration) 과 지속적 배포(Continuous Deployment) 서론 현재 자그만 토이 프로젝트를 협업하여 진행 중인데, 팀원과 제대로 branch 충돌을 해결하지 못해 일어나는 에러와, 수작업으로 EC2에 접속하여 직접 배포를 해야 하는 사소하지만 작업들이 dkswnkk.tistory.com CI/CD를 적용하는 이유는 이전에 작성한 게시글이 있으니 참고해주시면 감사하겠습니다. 기본적으로 EC2는 생성되어있다고 가정하고 진행하겠습니다. 환경 EC2(Amazone..
2022.12.04
-
Actuator Refresh 반영 안되는 현상 해결
문제 프로젝트 버전 Spring Cloud Config Server: Spring Boot 2.7.4 각각의 서비스 서버들: Spring Boot 2.7.4 Spring Discovery Server: Spring Boot 2.7.4 Spring GateWay Server: Spring Boot 2.7.4 현재 상황은 위의 이미지처럼 Spring Cloud Conifg 서버를 띄운 후 각각의 Spring Boot Application에서 해당 Config 서버로부터 설정 정보를 가져오고 있습니다. 이때 Config Server의 내용이 변경되었을 때 수정된 내용을 각각의 Spring Boot Application에 반영하는 방법은 다음과 같습니다. 서버 재기동 Actuator Refresh Spring ..
2022.11.12
-
Actuator dependency and Swagger Stater 3.0.0 충돌 에러
상황 현재 Spring Boot 2.7.4 버전을 사용하고 있고, Swagger 3.0.0 버전을 이용하고 있는 도중 Actuator dependency를 추가하였더니 아래와 같은 에러가 발생하면서 실행되지 않았습니다. 더보기 Error org.springframework.context.ApplicationContextException: Failed to start bean 'documentationPluginsBootstrapper'; nested exception is java.lang.NullPointerException at org.springframework.context.support.DefaultLifecycleProcessor.doStart(DefaultLifecycleProcessor.j..
2022.11.11
-
JUnit5 자세히 알아보기
목차 JUnit5란? JUnit5 구성 JUnit5 시작하기 JUnit5의 어노테이션들 JUnit5 테스트 이름 표시하기 JUnit5 Assertion 조건에 따라 테스트 실행하기 태깅과 필터링 테스트 반복하기 테스트 인스턴스 테스트 순서 1. JUnit5란? Junit란 테스팅 기반 프레임워크로써 자바 개발자가 가장 많이 사용하는 프레임워크입니다. 테스트 주도 개발(Test Driven Development, TDD)을 위해 사용합니다. 요구사항을 검증하는 테스트 케이스 작성 테스트 통과를 위한 코드 작성 이후 리팩토링하여 실제 개발 코드에 적용 2. JUnit5 구성 JUnit5는 Java8버전 이상부터 사용이 가능하며 Platform, Jupiter, Vintage 이 세 가지가 결합한 형태로 이루..
2022.10.02
-
[Spring] StringUtils 유용한 메서드 정리
org.springframework.util 패키지의 StringUtils 클래스에는 손쉽게 문자열을 다룰 수 있는 다양한 메서드를 제공하고 있습니다. 이번 게시글에서는 StringUtils에서 제공하는 문자열을 형식을 체크할 수 있는 몇 가지 메서드에 대해서 정리해 보겠습니다. StringUtils의 모든 메서드는 아래의 공식 문서에서 확인 가능합니다. StringUtils (Spring Framework 5.3.22 API)Check whether the given CharSequence contains actual text. More specifically, this method returns true if the CharSequence is not null, its length is greater..
2022.08.31
-
[GitHub] README.md에 블로그 최신 글 가져오기
위 이미지와 같이 GitHub README에 내 블로그 최신 글을 자동으로 주기적으로 가져오고 README에 작성되도록 하는 방법에 대해 정리해보겠습니다. (티스토리 기준) 과정은 다음과 같습니다. Python으로 블로그 피드(RSS) 크롤링 GitHub Actions를 활용하여 Workflow 생성 1. RSS 크롤링 테스트 먼저 티스토리 피드가 잘 불러와지는지 테스트를 진행합니다. (테스트이며, 필수는 아닙니다. 2번으로 넘어가셔도 됩니다.) import feedparser URL="https://dkswnkk.tistory.com/rss" # URL = "내블로그 주소/rss" RSS_FEED = feedparser.parse(URL) print(RSS_FEED) URL부분에 자신의 블로그 주소를 ..
2022.08.29
-
AssertJ 핵심 기능 알아보기
AssertJ란? ⭐️ 테스트에 관련된 많은 기능을 제공하고 메서드 체이닝으로 가독성 높은 테스트 코드 작성을 지원하는 오픈 라이브러리입니다. ⭐️ assertThat(검증대상)로 시작하며 메서드 체이닝을 이용하여 검증 메서드를 연쇄적으로 더 깔끔하고 가독성 있게 테스트 코드를 작성할 수 있습니다. 학습 환경 plugins { id 'org.springframework.boot' version '2.7.2' id 'io.spring.dependency-management' version '1.0.12.RELEASE' id 'java' } group = 'com.example' version = '0.0.1-SNAPSHOT' sourceCompatibility = '11' configurations { c..
2022.08.08
-
[Querydsl] unable to load class com.mysema.codegen.model.type'. error
문제 현재 프로젝트는 spring-boot-2.7.2를 사용 중이며, Querydsl을 사용하기 위해 build.gradle에 의존성을 추가하는 과정에서 위와 같은 에러가 발생했습니다. plugins { id 'org.springframework.boot' version '2.7.2' id 'io.spring.dependency-management' version '1.0.12.RELEASE' // querydsl 추가 id "com.ewerk.gradle.plugins.querydsl" version "1.0.10" id 'java' } group = 'study' version = '0.0.1-SNAPSHOT' sourceCompatibility = '11' configurations { compil..
2022.07.31
-
[Java] 자바에서 '+' 연산을 통한 문자열 합치기를 지양하라
서론 자바에서 '+' 연산을 통한 문자열 합치기를 지양하라는 흥미로운 주제를 보게 되어 글을 작성하게 되었습니다. 그전에 먼저 String과 StringBuffer, 그리고 StringBuilder에 대한 사전 지식이 있으면 이해하기 수월합니다. 해당 내용은 아래 게시글에서 정리한 적이 있습니다. [Java] StringBuffer와 StringBuilder 서론 [Java] String 클래스 서론 c언어 같은 경우 문자열을 char형의 배열로 다루었지만 자바에서는 문자열을 위한 클래스를 제공합니다. 그것이 바로 String 클래스인데, String 클래스는 문자열을 저장 dkswnkk.tistory.com [Java] String 클래스 서론 c언어 같은 경우 문자열을 char형의 배열로 다루었지만 ..
2022.07.19
-
CORS(교차 출처 리소스 공유)란?
서론 백엔드를 개발하면서 프런트 개발자와 협업을 진행하다 보면 한 번쯤은 위 이미지처럼 CORS 에러에 대해 맞닥뜨린 적이 있을 것입니다. 이번 게시글에서는 이러한 CORS가 뭔지, 그리고 왜 발생하고 어떻게 해결할 수 있는지 한번 정리해 보겠습니다. SOP(Same Origin Policy) CORS를 알기 전에 먼저 SOP라는 개념에 대해 먼저 알아야 합니다. 동일 출처 정책(same-origin policy)은 어떤 출처(origin)에서 불러온 문서나 스크립트가 다른 출처에서 가져온 리소스와 상호작용하는 것을 제한하는 보안 방식입니다. 동일 출처 정책은 잠재적으로 해를 끼칠 수 있는 요청을 분리함으로써 공격받을 수 있는 경우를 줄여줍니다. 여기서 출처(origin)는 접근할 때 사용하는 URL의 ..
2022.07.14
-
SSO(Single Sign-On) 통합인증 이란?
서론 현재 일하고 있는 곳에서는 내부망에서 다양한 시스템들을 운영하고 있습니다. 여기서 주목한 점은 한 번의 로그인으로 내부의 모든 시스템을 재 로그인 없이 이용할 수 있는 방식인 SSO(Single Sign On) 인증 방식입니다. 이번 게시글에서는 이러한 SSO(Single Sign On)에 대해서 한번 정리해 보겠습니다. SSO란? SSO는 Single-Sign-On의 약자로 한 번의 로그인으로 여러 개의 사이트들을 재 로그인 없이 이용하는 방법을 말하며, 통합인증이라고도 부릅니다. 위 이미지는 SSO가 아닌 방식입니다. 일반적으로 위 이미지처럼 서로 다른 시스템은 서로 각각의 사용자 인증 방식이 필요합니다. 카카오톡 로그인을 했다고 해서 페이스북을 추가적인 로그인 없이 이용할 수 없고, 마찬가지로..
2022.07.13
-
[GitHub] submodule 사용해서 yml과 같은 민감한 정보 숨기기
서론 보통 프로젝트를 진행하다 보면 GitHub 상에서 보여주고 싶지 않은 민감한 정보들이 있습니다. Spring Boot로 프로젝트를 진행할 때 DB의 계정 등을 담을 .yml파일들을 예로 들 수 있습니다. 프로젝트 자체를 private로 설정해서 노출을 방지하는 방법도 있겠지만 submodule을 사용하면 특정 폴더만 private로 설정해서 노출을 막을 수 있습니다. 따라서 이번 게시글에서는 git submodule에 대해서 알아보고, Spring Boot 환경에서 yml파일들을 숨겨보는 방법을 정리해 보겠습니다. 구체적인 과정 1. public repository 생성 먼저 위와 같이 public repository를 만듭니다. 저는 기초적인 spring boot 프로젝트를 하나 생성했습니다. 기..
2022.07.10
-
Sourcetree "permission denied (publickey)" error 해결
문제 Sourcetree를 이용해 push를 하는 과정에서 "permission denied (publickey)" 문제가 발생해서 진행이 되지 않았습니다. 해당 문제는 SSH 인증에 문제가 있을 경우 발생하는데, 아래와 같은 방법으로 해결이 가능합니다. 해결 1. ssh-keygen "파일 이름"을 입력하여 새로운 ssh를 생성합니다. 사용할 비밀번호까지 입력하게 되면 지정한이름.pub 형식으로 파일이 생성됩니다. 2. cat 파일이름.pub을 통해서 생성된 키 값을 복사합니다. 파란색으로 칠해진 문자만 복사하면 됩니다. 3. GitHub -> Settings -> SSH and GPG keys -> New SSH key에서 2번에서 복사한 키를 입력해 줍니다. 4.ssh-add -l 를 입력합니다. ..
2022.07.06
-
[git] Git - HEAD
Git Head 모든 브렌치에는 HEAD값이 존재하는데, HEAD는 브렌치의 마지막 커밋 즉 현재 속한 브랜치의 가장 최신 커밋을 의미합니다. 작업 트리에 변화를 주는 git 명령어들은 대부분 HEAD를 변경하는 것으로 시작합니다. 예시 checkout으로 앞뒤 이동 ⭐️ ^ 또는 ~: 갯수만큼 해당 브렌치의 이전(옛날)으로 이동 git checkout HEAD^ git checkout HEAD^^^ git checkout HEAD~5 ⭐️ -: 해당 브랜치의 한 단계 최근 커밋으로 이동 git checkout - ⭐️ 커밋 해시를 사용해서도 이동 가능 git checkout (커밋해시) 커밋 해시는 git log 명령어를 통해 아래와 같이 밑줄 그인 곳에서 확인이 가능합니다.
2022.07.03
-
[git] .gitignore 형식 정리
서론 .gitignore 파일이란 git version 관리에서 제외할 파일 목록을 설정하는 파일입니다. .gitignore 파일은 항상 Project의 최상위 Directory에 위치해야 하며 사용 형식은 아래와 같습니다. '#'로 시작하는 라인은 무시한다. 표준 Glob 패턴을 사용한다. 슬래시(/)로 시작하면 하위 디렉터리에 적용되지(recursivity) 않는다. 디렉터리는 슬래시(/)를 끝에 사용하는 것으로 표현한다. 느낌표(!)로 시작하는 패턴의 파일은 무시하지 않는다. 예제 # 이렇게 #를 사용해서 주석 # 모든 file.c file.c # 최상위 폴더의 file.c /file.c # 모든 .c 확장자 파일 *.c # .c 확장자지만 무시하지 않을 파일 !not_ignore_this.c # ..
2022.07.02
-
[OOP] 객체지향 설계 원칙 5가지
서론 다들 객체지향 설계의 5원칙이라고 불리는 SOLID에 대해서 한번쯤을 들어봤을 겁니다. 객체지향에서 꼭 지켜야할 5개의 원칙을 통틀어 5원칙이라고 칭하고, 이 5개의 원칙의 앞글자를 따서 SOLID라고도 부릅니다. 클린코드의 저자로 유명한 로버트 마틴이 2000년대 초반에 명명하였으며, 프로그래머가 시간이 지나도 유지 보수와 확장이 쉬운 시스템을 만들고자 할 때 이 원칙들을 함께 적용할 수 있습니다. 각각의 원칙들은 아래와 같습니다. 단일 책임 원칙(SRP, Single Responsibility Principle) 개방 폐쇄 원칙(OCP, Open-Closed Principle) 리스코프 치환 원칙(LSP, Liskov Subsituation Principle) 인터페이스 분리 원칙(ISP, In..
2022.06.02
-
[CI/CD] CI/CD란?, 지속적 통합(Continuous Integration) 과 지속적 배포(Continuous Deployment)
서론 현재 자그만 토이 프로젝트를 협업하여 진행 중인데, 팀원과 제대로 branch 충돌을 해결하지 못해 일어나는 에러와, 수작업으로 EC2에 접속하여 직접 배포를 해야 하는 사소하지만 작업들이 신경 쓰이게 되었습니다. 저는 이 프로젝트에 GitHub Action을 이용하여 CI/CD를 적용했는데 이번 게시글에서는 이러한 작업들을 자동화시켜주는 CI/CD에 대해서 알아보고 다음 게시글에서는 여러 개의 CI/CD 툴 중 GitHub Action을 이용한 CI/CD 적용에 대해서 정리해 보겠습니다. CI(Continuous Integration) CI(Continuous Integration)는 "지속적인 통합" 이라는 의미로, 요약하자면 빌드/테스트 자동화 과정입니다. 애플리케이션에 대한 새로운 코드 변경..
2022.05.31
-
[AWS] ec2 인스턴스 및 RDS 사라짐 현상
문제 기존에 돌아가고 있던 인스턴스를 내버려두고 새로운 인스턴스를 생성했더니 기존에 있던 인스턴스와 생성한 인스턴스까지 모두 사라지는 현상이 발생했습니다. 더군다나 작업 중이던 RDS까지 전부 aws 홈페이지 상에서 보이지가 않았습니다. 하지만 DataGrip에서 DB도 정상적으로 연동되고, WAS도 정상적으로 돌아갔습니다. 분명 서버는 정상적으로 가동 중인데 AWS홈페이지 상에서만 보이지 않는 현상이었습니다. 해결 해당 문제는 리전이 달라서 발생한 문제였습니다. 새로운 인스턴스를 생성하고 나서 리전이 버지니아 북부로 선택되어 있었습니다. 왜 버니지아 북부로 리전이 선택되어 있는지는 모르겠지만 이전 인스턴스들은 당연히 서울/아시아로 생성되었기에 현재 리전인 버지니아 북부 카테고리에서는 보이지 않는 것이었..
2022.05.30
-
[MySQL] UPSERT (ON DUPLICATE KEY UPDATE)
서론 MySQL에서 UPDATE 문구는 해당 데이터가 존재할 때만 UPDATE를 수행합니다. 프로젝트를 진행하면서 덮어 씌우기 기능 즉, 데이터가 존재할 경우 UPDATE를 수행하고, 존재하지 않다면 INSERT를 수행하는 기능이 필요했습니다. 사실 비즈니스 로직에서 검증 후 결과에 따라 분기 쿼리를 날려도 되지만 혹시나 원하는 기능이 있을까 싶어서 찾아보게 되었습니다. MySQL UPSERT UPSERT는 이름에서도 보이듯이 UPDATE와 INSERT를 합친 단어입니다. MySQL에서는 이러한 UPSERT 기능을 4.1 이상 버전부터 지원합니다. 즉, UPSERT는 중복되는 값(UNIQUE KEY)이 있다면 UPDATE를 수행하고, 중복되는 값이 없다면 INSERT를 수행합니다. UPSERT는 ON D..
2022.05.23
-
[Spring] [BaseTimeEntity, JPA Auditing]을 통한 생성시간/수정시간 자동화
서론 보통 엔티티(entity)에는 해당 데이터의 생성 시간과 수정시간을 포함한 컬럼이 항상 존재합니다. 언제 만들어졌는지, 언제 수정되었는지 등은 차후 유지보수에 있어 굉장히 중요한 정보이며, 데이터 분석에 유용하기 때문입니다. 그렇다 보니 매번 DB에 삽입(insert) 하기 전, 갱신(update) 하기 전에 날짜 데이터를 등록/수정하는 코드가 여기저기 들어가게 됩니다. 하지만 모든 엔티티마다 생성시간과 수정시간을 넣는다면 코드가 매우 지저분해지고 객체지향적이지 못합니다. 이러한 문제는 JPA Auditing를 사용하면 쉽게 해결할 수 있습니다. LocalDate 사용 Java8부터 LocalDate와 LocalDateTime이 등장했습니다. 사실 그동안은 Java의 기본 날짜 타입인 Date를 사..
2022.05.22
-
[Spring] @Valid, @ControllerAdvice, @Exception을 이용한 데이터 검증 및 처리
서론 보통 @ControllerAdvice와 @ExceptionHandler를 이용하여 예외처리를 분리 및 통합하여 처리합니다. 이때 @Valid 어노테이션을 이용하여 데이터를 검증하고, 해당 데이터에 에러가 있을 경우 필드에 적용했던 예외 메시지만 깔끔하게 가져오는 방법이 궁금했습니다. 다시 말해 public class User { private String name; @Min(value = 19, message = "나이는 19살 이상이어야 합니다.") private int age; } 위와 같은 Entitiy일 때 나이를 10살로 하고 Post를 하였을 때 아래 이미지의 첫 번째 결과가 아니라 두 번째 결과처럼 details 부분에서 default message인 "나이는 19살 이상이어야 합니다...
2022.05.20
-
[Java] 내부 클래스(inner class) 와 익명 클래스(anonymous class)
서론 람다식에 대해서 학습하다가 익명 객체라는 용어가 자주 나왔고, 익명 객체를 학습하다 보니 최종적으로 inner class에 도달하게 되었습니다. 내부 클래스(inner class)는 사실 클래스 내에 선언된다는 점을 제외하고는 일반적인 클래스와 다르지 않습니다. 내부 클래스에는 인스턴스 클래스, 스태틱 클래스, 지역 클래스, 익명 클래스의 종류로 나눌 수 있는데 한번 자세하게 정리해 보겠습니다. 목차 1. 내부 클래스란? 2. 내부 클래스의 종류와 특징 3. 내부 클래스의 선언 4. 내부 클래스의 제어와 접근성 5. 익명 클래스(anonymous class) 1. 내부 클래스란? 내부 클래스는 클래스 내에 선언된 클래스입니다. 한 클래스를 다른 클래스의 내부 클래스로 선언하면 두 클래스의 멤버들 간..
2022.05.18
-
[Java] (Project, Package, Class, Method) Naming 규칙
공통 대소문자가 구분되며 길이에 제한이 없다. 예약어를 사용해서는 안 된다. 숫자로 시작해서는 안 된다. 특수문자는 '_' 혹은 '$'만 허용한다. 파스칼 표기법(PascalCase)과 카멜 표기법(camelCase)을 사용한다. 반의어는 반드시 대응하는 개념으로 사용해야 한다. 1. Project(프로젝트) 대/소문자 구분없이 시작 가능하다. 대문자 사용을 권장한다. 2. Package(패키지) 패키지명은 대소문자를 모두 허용 하지만 클래스명과 쉽게 구분하기 위해서 소문자로 하는 것을 원칙 으로 하고 있다. 표준 패턴을 따른다. Ex) [com].[Company].[Project].[toppackage].[lowerpackage] 가급적 한 단어 사용을 권장한다. 좋은 예: com.nexon.maple..
2022.05.16
-
[Spring] nested exception is java.lang.NullPointerException
서론 spring boot 2.6.7을 사용 중이고 swagger 3.0.0 버전을 이용하기 위해 진행하던 중 아래와 같은 오류가 발생했습니다. Failed to start bean 'documentationPluginsBootstrapper'; nested exception is java.lang.NullPointerException 현재 gradle을 사용중이기에 아래와 같이 dependencies에는 아래와 같이 추가해 주었습니다. implementation 'io.springfox:springfox-boot-starter:3.0.0' maven일 경우 아래와 같이 추가하면 됩니다. io.springfox springfox-swagger2 3.0.0 io.springfox springfox-swag..
2022.05.15
-
[Spring] 객체복사 BeanUtils.copyProperties
서론 스프링을 공부하다 보면 객체의 값을 그대로 복사해야 하는 경우가 있습니다. 그럴 때 Setter 메서드로 일일이 모두 작성하는 것은 코드의 길이와 작성 시간이 늘어나고, 가독성이 떨어지게 됩니다. 이때 BeanUtils.copyProperties를 통해 한 줄로 해결할 수 있습니다. 또한, 원하지 않는 값들은 추려내어 원하는 값들만 복사할 수도 있습니다. BeanUtils.copyProperties copyProperties은 Spring에서 제공하는 BeanUtils 클래스의 메서드입니다. 사용법은 아래와 같습니다. BeanUtils.copyProperties(Object source, Object target, String... ignoreProperties) source: 원본 객체 targe..
2022.05.15
-
[Java] String format() method
String format() method java string format() 메서드는 지정된 Locale, format 및 arguments로 형식이 지정된 문자열을 반환합니다. String.format() 메서드에서 Locale(국가)을 지정하지 않으면 Locale.getDefault() 메서드를 호출하여 기본 Locale을 사용합니다. Java에서의 format() 메서드는 C 언어의 printf() 함수와 같습니다. 세부 구현 String format() 메서드의 세부 구현은 아래와 같으며, 두 가지 유형이 있습니다. public static String format(String format, Object... args) { return new Formatter().format(format, ar..
2022.05.14
-
[MySQL] SELECT 문에서 NULL 값 치환하기
IFNULL(?, ?) 컬럼이 NULL이면 0으로 치환하여 반환 SELECT IFNULL(컬럼명, 0) FROM TEST ; 컬럼이 NULL이면 -- 으로 치환하여 반환 SELECT IFNULL(컬럼명, '--') FROM TEST ; IF() 컬럼이 NULL일 경우 1을, NULL이 아닐때는 2를 return한다. SELECT IF(컬럼명 IS NULL, '1', '2') FROM 테이블명 NULLIF(?, ?) (전자 == 후자) 의 결과가 false면 전자의 값을 return 하고, true이면 NULL을 return 한다. SELECT NULLIF(1, 1) ; --> null 을 리턴한다. SELECT NULLIF(1, 2) ; --> 1을 리턴한다.
2022.05.12
-
[Java] Object to int
서론 Java의 Object 클래스는 java.lang 패키지 중에서 가장 많이 사용되는 클래스이며, 모든 자바 클래스의 최고 조상 클래스입니다. 이번 게시글에서는 Object 타입을 int타입으로 캐스팅하는 방법에 대해서 한번 정리해 보겠습니다. 방법 1. Object의 값이 Integer라면 아래와 같은 방법을 이용할 수 있습니다. int i = (Integer) object; 2. 만약 자바 7 이상이라면 아래와 같은 같은 방식으로도 가능합니다. int i = (int) object; Object가 Interger가 아니라면 ClassCastException에러가 발생할 수도 있으며, Object가 null일 경우에는 NullPointerException이 발생하기에 Object의 타입이 Inter..
2022.05.06
-
[Spring] properties encoding 하기(국제화 한글깨짐)
서론 스프링 학습 중 다국어 처리를 하기 위해 국제화(Internationalization) 처리를 하다가 이상하게 한글만 정상적으로 처리가 되지 않았습니다. 아래와 같이 정상적으로 Bean 등록도 해주었고, Controller, yml 설정, message 번들까지 완벽하게 구성했는데도 오직 한글 부분만 오류가 발생했습니다. main @SpringBootApplication public class ApiPracticeApplication { public static void main(String[] args) { SpringApplication.run(ApiPracticeApplication.class, args); } @Bean public LocaleResolver localeResolver() {..
2022.04.27
-
클라우드의 이해: IaaS, PaaS, SaaS
서론 AWS의 EC2 환경에서 인프라를 계속 설계하다 보니 클라우드 컴퓨터의 개념에 대해 궁금해져서 찾아보게 되었습니다. 클라우드 컴퓨팅은 인터넷으로 가상화된 IT 리소스를 서비스로 제공하는 것을 의미합니다. 그리고 클라우드 컴퓨팅에서 가상화하여 서비스로 제공하는 대상은 서버, 플랫폼, 소프트웨어입니다. AWS(아마존 웹서비스)에서 제공하는 클라우드 서비스들이 대중화되면서 클라우드를 인프라스트럭쳐의 가상화 개념으로만 이해하기도 하지만 클라우드는 인프라스트럭쳐뿐만 아니라 플랫폼과 소프트웨어까지 포함하는 온라인의 모든 영역을 다루는 꽤 광범위한 개념입니다. 이번 게시글에서는 가상화 대상에 따라 나눈 인프라스트럭쳐 클라우드, 플랫폼 클라우드, 소프트웨어 클라우드에 대해 정리해 보겠습니다. 인프라스트럭쳐 클라우..
2022.04.25
-
API vs Library vs Framework
서론 API와 라이브러리, 그리고 프레임워크 세 단어의 차이점에 대해서 머릿속으로는 쉽게 떠오르지만 막상 정확한 차이가 뭐냐고 물어보면 논리적으로 설명하기가 힘듭니다. 그래서 이번 기회에 글을 정리함으로써 한번 단단히 개념을 잡고자 합니다. 목차 1. API란? 2. 라이브러리란? 3. 프레임워크란? 4. API와 라이브러리의 차이 5. 라이브러리와 프레임워크의 차이 API(Application Programming Interface) API(Application Programming Interface)란 응용 프로그램에서 사용할 수 있도록, 운영체제나 프로그래밍 언어가 제공하는 기능을 제어할 수 있게 만든 인터페이스를 뜻합니다. - 위키백과 쉽게 예시를 들어서 설명하면 API는 레스토랑의 '점원'입니다..
2022.04.25
-
Nginx란 무엇인가?
서론 토이 프로젝트를 진행하면서 웹 서버로 Nginx를 사용하게 되었는데, 단순히 사용만 하는 것이 아니라 개념부터 확실하게 잡고 가기 위해서 정리를 하게 되었습니다. 웹 서버에 대한 개념은 아래 게시글에서 정리한 적이 있으니 참고하시면 좋을 것 같습니다. Web Server와 WAS의 차이 서론 웹 서버(Web Server)와 웹 애플리케이션 서버(Web Application Server)의 키워드만 두고 보았을 때 두 개의 차이가 뭔가에 대해 확신 있게 대답을 못할뿐더러 아직 이해가 잘 가지 않아서 한번 정리를 dkswnkk.tistory.com 또한 Nginx를 설명하기 위해선 또 다른 웹 서버인 Apache와 비교하게 되는 될 수밖에 없기에, 이번 게시글에서는 Nginx와 Apache의 성능을 비..
2022.04.20
-
Forward Proxy와 Reverse Proxy
서론 이전 게시글에서 WebServer와 WAS에 대해서 정리를 했습니다. 추가적으로 Forward Proxy와 Reverse Proxy의 개념도 나오는데 이번 시간에는 이러한 프록시의 개념에 대해 알아보겠습니다. WebServer와 WAS에 대한 개념은 아래 게시글에서 정리한 적이 있으니 참고하시면 좋을 것 같습니다. Web Server와 WAS의 차이 서론 웹 서버(Web Server)와 웹 애플리케이션 서버(Web Application Server)의 키워드만 두고 보았을 때 두 개의 차이가 뭔가에 대해 확신 있게 대답을 못할뿐더러 아직 이해가 잘 가지 않아서 한번 정리를 dkswnkk.tistory.com 먼저 프록시(Proxy)라는 용어에 대해 알아보고 Forward Proxy와 Reverse ..
2022.04.18
-
URI, URL, 그리고 URN
서론 URI와 URL의 차이가 무엇일까요? 주소는 URL이라고 부르는데 URI는 무엇을 의미하는지 감이 잡히지 않아서 이번 게시글을 정리하면서 URI와 URL의 차이에 대해 알아보고 그리고 추가로 URN에 대해서도 알아보겠습니다. 목차는 아래와 같습니다. URI란 무엇인가? URL은 무엇인가? URN은 무엇인가? 1. URI(Unifrom Resource Identifier) URI(Unifrom Resource Identifier, URI)는 통합 자원 식별자로 인터넷에 있는 자원을 나타내는 유일한 주소입니다. URI의 존재는 인터넷에서 요구되는 기본 조건으로써 인터넷 프로토콜에 항상 붙어 다닙니다. 또한 URI는 로케이터(locatior), 이름(name) 또는 둘 다 추가로 분류될 수 있습니다. 프..
2022.04.16