Dockerfile

📌 Dockerfile은 컴퓨터에서 돌아가는 앱을 만들기 위한 레시피라고 보면 된다. 이 레시피대로 하면 Docker 이미지라는 걸 만들 수 있다. Docker 이미지는 앱을 실행하는 데 필요한 모든 것을 담고 있다.

 

 

Dockerfile을 사용하는 이유

 

1. 환경 일관성

  • 문제: 애플리케이션은 다양한 환경(OS, 라이브러리 버전, 설정)에 따라 다르게 동작할 수 있습니다.
  • Dockerfile의 역할:
    • Dockerfile을 통해 운영체제, 소프트웨어 버전, 라이브러리 등을 명시적으로 정의.
    • 개발, 테스트, 운영 환경에서 동일한 컨테이너 이미지를 사용하므로 환경 차이로 인한 문제를 방지.
    • "개발 환경에서 잘 동작하는데 프로덕션에서는 오류가 발생하는 문제"를 해소.

2. 자동화된 이미지 생성

  • 문제: 매번 애플리케이션을 설치하거나 빌드하는 과정을 수동으로 처리하면 시간이 낭비되고 오류가 발생할 수 있습니다.
  • Dockerfile의 역할:
    • Dockerfile은 애플리케이션 빌드 및 설치 과정을 자동화.
    • docker build 명령어로 간단히 이미지를 생성할 수 있음.
    • 변경 사항이 생길 경우 Dockerfile만 업데이트하여 쉽게 새로운 이미지를 생성 가능.

3. 이식성(Portability)

  • 문제: 다른 플랫폼(OS)에서 애플리케이션을 배포하려면 추가 설정과 조정이 필요할 수 있습니다.
  • Dockerfile의 역할:
    • Docker 이미지는 한 번 생성하면 어떤 환경에서든 동일하게 동작.
    • 컨테이너를 실행할 수 있는 곳이라면(로컬, 클라우드, 서버 등) 어디서나 배포 가능.
    • 운영 환경에 상관없이 안정적인 배포 보장.

4. 확장성과 모듈화

  • 문제: 복잡한 시스템은 여러 애플리케이션이나 서비스가 상호작용하며 구성됩니다.
  • Dockerfile의 역할:
    • Dockerfile을 사용해 애플리케이션별 컨테이너를 생성하고, 이를 조합하여 마이크로서비스 아키텍처를 구현.
    • 각 서비스는 독립적으로 배포, 확장 가능.

5. 버전 관리 및 재현성

  • 문제: 애플리케이션 업데이트나 변경이 과거 버전과 충돌하거나 재현이 어려울 수 있음.
  • Dockerfile의 역할:
    • Dockerfile 자체를 소스 코드와 함께 버전 관리(Git 등)할 수 있음.
    • 특정 시점의 Dockerfile로 언제든지 동일한 이미지를 재생성 가능.

6. 배포 자동화(CI/CD와 통합)

  • 문제: 애플리케이션 배포 과정을 수동으로 처리하면 효율성이 떨어지고 오류가 발생할 수 있음.
  • Dockerfile의 역할:
    • CI/CD 파이프라인에서 Dockerfile을 사용해 자동으로 이미지를 생성하고 테스트, 배포 가능.
    • GitHub Actions, Jenkins, GitLab CI/CD 등과 쉽게 통합 가능.

7. 리소스 격리

  • 문제: 하나의 서버에서 여러 애플리케이션을 실행하면 서로 충돌할 가능성이 있음.
  • Dockerfile의 역할:
    • 컨테이너화된 애플리케이션은 호스트와 격리된 상태로 실행.
    • 리소스(CPU, 메모리, 네트워크)를 독립적으로 관리 가능.

8. 경량성

  • 문제: VM(가상 머신)은 운영체제와 함께 많은 리소스를 소모.
  • Dockerfile의 역할:
    • 컨테이너는 운영체제를 포함하지 않으므로 VM에 비해 가볍고 빠름.
    • Dockerfile로 필요한 최소 구성만 정의해 경량화된 이미지를 생성.

요약: Dockerfile 사용하는 이유

이유  설명
환경 일관성 개발, 테스트, 운영 환경 간 차이를 없애 동일한 애플리케이션 동작 보장.
자동화 애플리케이션 빌드 및 설정 과정을 자동화.
이식성 어디서나 동일하게 실행 가능한 이미지를 제공.
확장성 마이크로서비스 아키텍처 및 독립적인 서비스 확장을 지원.
재현성 버전 관리를 통해 특정 시점의 동일 환경을 재생성 가능.
CI/CD 통합 자동화된 빌드와 배포를 지원하여 DevOps 환경에 최적화.
격리 및 안전성 컨테이너 간 리소스 격리로 안정성 향상.
경량성 VM보다 적은 리소스 사용으로 효율적.

 

 

Dockerfile 사용법

 

Dockerfile 예제

# Dockerfile
FROM ubuntu:latest  # 베이스 이미지를 Ubuntu 최신 버전으로 설정
MAINTAINER Your Name <your-email@example.com>  # 이미지 제작자 정보

# 필요한 패키지 업데이트 및 Nginx 설치
RUN apt-get update && apt-get install -y nginx  

# index.html 파일을 Nginx의 기본 HTML 디렉토리로 복사
COPY index.html /usr/share/nginx/html  

# 컨테이너가 노출할 포트를 설정
EXPOSE 80  

# 컨테이너 실행 시 Nginx를 실행하고 데몬 모드를 비활성화
CMD ["nginx", "-g", "daemon off;"]  

Dockerfile 명령어 설명

명령어 설명
FROM 베이스 이미지를 설정 (컨테이너의 기반 OS 또는 환경).
MAINTAINER 이미지를 제작한 사람의 이름과 이메일 주소를 설정.
RUN 컨테이너 이미지를 빌드할 때 실행할 명령어 (예: 패키지 설치).
COPY 로컬 파일을 컨테이너 이미지로 복사.
EXPOSE 컨테이너가 외부에 노출할 포트를 지정.
CMD 컨테이너가 실행될 때 기본으로 실행할 명령어를 설정.

Docker 이미지 생성 명령어

  1. Docker 이미지를 생성하는 명령:
    docker buildx build -t my-nginx:latest .
    
    • -t: 이미지에 태그를 설정 (예: my-nginx:latest).
    • .: 현재 디렉토리에서 Dockerfile을 찾음.
    • buildx: 빌드 실행 도구. 일반적인 빌드 명령은 docker build를 사용.

Docker 컨테이너 실행 명령어

  1. 컨테이너 실행 명령:
    docker run -d -p 80:80 my-nginx:latest
    
    • -d: 컨테이너를 백그라운드에서 실행.
    • -p 80:80: 호스트의 80번 포트를 컨테이너의 80번 포트에 매핑.
    • my-nginx:latest: 생성한 Docker 이미지를 기반으로 컨테이너 실행.

Docker 컨테이너 관리

  1. 컨테이너 종료:
    • my-nginx: 실행 중인 컨테이너 이름 또는 ID.
  2. docker stop my-nginx
  3. 컨테이너 재시작:
  4. docker start my-nginx
  5. 실행 중인 컨테이너 확인:
  6. docker ps
  7. 중지된 컨테이너 포함 확인:
  8. docker ps -a

Docker 이미지 공유

  1. Docker 레지스트리:
    • Docker 이미지를 공유하고 저장하는 서비스.
    • 예: Docker Hub, AWS ECR, Google Container Registry 등.
  2. 이미지 업로드 명령:
    • username/my-nginx:latest: Docker Hub에 업로드할 이미지 이름.
    • Docker Hub에 업로드하려면 먼저 docker login으로 인증 필요.
  3. docker push username/my-nginx:latest
  4. 이미지 다운로드 명령:
    • 공유된 이미지를 다른 사용자나 서버에서 다운로드하여 사용.
  5. docker pull username/my-nginx:latest

정리된 작업 흐름

  1. Dockerfile 작성:
    • 애플리케이션과 설정을 정의.
  2. 이미지 생성:
    • docker build 명령으로 이미지를 생성.
  3. 컨테이너 실행:
    • docker run 명령으로 컨테이너 실행.
  4. 컨테이너 관리:
    • 컨테이너를 start, stop, restart 명령으로 제어.
  5. 이미지 공유:
    • Docker Hub 등 레지스트리에 이미지를 업로드하여 협업 또는 배포.

Dockerfile 명령어

명령어 설명  예제
FROM 베이스 이미지를 지정. Dockerfile은 항상 FROM으로 시작. FROM ubuntu:22.04
MAINTAINER Dockerfile 작성자 정보 (이제는 LABEL 사용 권장). MAINTAINER naebaecaem <nbcamp@spartacoding.co>
LABEL 이미지에 메타데이터 추가. LABEL purpose='nginx test'
RUN 이미지를 생성하는 동안 실행할 명령어. root 권한으로 실행. RUN apt update && apt upgrade -y
CMD 컨테이너 생성 시 실행할 명령어. 컨테이너 시작 시 한 번만 실행. CMD ["nginx", "-g", "daemon off;"]
ENTRYPOINT 컨테이너 시작 시 무조건 실행할 명령어. 추가 명령어와 결합 가능. ENTRYPOINT ["npm", "start"]
ENV 환경 변수를 설정. ENV STAGE stagingENV JAVA_HOME /usr/lib/jvm/java-8-oracle
WORKDIR 작업 디렉토리를 설정. WORKDIR /app
COPY 호스트의 파일/디렉토리를 컨테이너에 복사. Docker Context 내의 파일만 가능. COPY index.html /usr/share/nginx/html
USER 컨테이너 내에서 사용할 기본 사용자를 설정. USER userRUN ["useradd", "user"]
EXPOSE 컨테이너에서 노출할 포트를 설정. EXPOSE 80
ARG 빌드 시점에 전달할 변수를 설정. ENV와 달리 빌드 후에는 사라짐. ARG STAGERUN sh -c 'echo "STAGE=$STAGE" > .env'

Dockerfile 예제 1: FastAPI 앱 실행

# Python 3.11 베이스 이미지 사용
FROM python:3.11

# pipenv 설치
RUN pip install pipenv

# 작업 디렉토리 설정
WORKDIR /app

# 로컬 파일을 컨테이너로 복사
ADD . /app/

# pipenv 환경 설정
RUN pipenv --python 3.11
RUN pipenv run pip install poetry
RUN pipenv sync
RUN pipenv run pip install certifi

# 빌드 시 입력 가능한 변수 설정
ARG STAGE
RUN sh -c 'echo "STAGE=$STAGE" > .env'
RUN sh -c 'echo "PYTHONPATH=." >> .env'

# 실행 스크립트에 실행 권한 부여
RUN chmod +x ./scripts/run.sh
RUN chmod +x ./scripts/run-worker.sh

# 컨테이너 시작 시 실행할 명령어 설정
CMD ["./scripts/run.sh"]

Dockerfile 예제 2: Nginx 웹 서버

Dockerfile

# Ubuntu 22.04 베이스 이미지 사용
FROM ubuntu:22.04

# 작성자 정보
MAINTAINER your-name <your-email@example.com>

# 이미지 메타데이터 추가
LABEL purpose=Web Server

# Nginx 설치
RUN apt-get update && apt-get install -y nginx

# Nginx 설정 파일 복사
COPY nginx.conf /etc/nginx/nginx.conf

# 컨테이너 실행 시 Nginx 시작
CMD ["nginx", "-g", "daemon off;"]

Nginx 설정 파일 (nginx.conf):

user  nginx;
worker_processes  1;

error_log  /var/log/nginx/error.log warn;
pid        /var/run/nginx.pid;

events {
    worker_connections  1024;
}

http {
    include       /etc/nginx/mime.types;
    default_type  application/octet-stream;

    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';

    access_log  /var/log/nginx/access.log  main;

    sendfile        on;
    keepalive_timeout  65;

    gzip  on;
    gzip_disable "msie6";

    include /etc/nginx/conf.d/*.conf;
}

 

'Docker > Docker' 카테고리의 다른 글

[Docker] Docker 모니터링&로깅  (0) 2025.02.04
[Docker] Docker Compose  (0) 2025.02.03
[CI/CD] Github Actions CI  (0) 2025.01.31
[Docker] Docker+CI/CD  (0) 2025.01.30
[Docker] Docker 기초  (0) 2025.01.29

Elasticsearch의 주요 기능

📌  Elasticsearch의 핵심 기능은 대용량 데이터에 대한 빠른 검색과 실시간 데이터 분석입니다.

 

  1. 🔍 전문 검색(Full-Text Search)
    • 형태소 분석(Tokenizer, Analyzer) 지원
    • 유사 검색, 오타 교정(Fuzzy Search), 자동 완성 기능 제공
    • match, term, bool 쿼리를 활용한 다양한 검색 조건 지원
      더보기
      더보기
      더보기
      더보기

      🔍 Elasticsearch의 Full-Text Search(전문 검색) 수행 방식

      Elasticsearch의 **Full-Text Search(전문 검색)**은 단순한 문자열 비교가 아니라, 문서를 토큰화(tokenization)하고, 형태소 분석을 수행한 후, **역색인(Inverted Index)**을 이용하여 빠르게 검색하는 방식입니다.


      1️⃣ 검색이 이루어지는 과정

      Elasticsearch에서 **전문 검색(Full-Text Search)**은 다음과 같은 단계를 거칩니다.

      1️⃣ 문서 저장(Indexing) 과정
      2️⃣ 검색어 분석(Query Parsing & Analysis)
      3️⃣ 역색인(Inverted Index) 조회
      4️⃣ 검색 결과 정렬(Scoring & Ranking)
      5️⃣ 결과 반환


      2️⃣ 검색 과정의 세부 구조

       

      🔹 1. 문서 저장(Indexing)

      Elasticsearch에서 데이터를 저장할 때, 단순한 문자열 형태가 아니라 토큰화(Tokenization) 및 형태소 분석(Analysis)을 수행하여 역색인(Inverted Index)을 생성합니다.

      예를 들어, 다음과 같은 문서를 저장한다고 가정하겠습니다.

      PUT my_index/_doc/1
      {
        "content": "엘라스틱서치는 강력한 검색 엔진입니다."
      }
      

      이 문장이 Elasticsearch에 저장될 때, 토큰화(Tokenization) 과정이 수행됩니다.

      📌 형태소 분석(예: standard 분석기 적용)

      [ "엘라스틱서치", "강력한", "검색", "엔진" ]
      
      • 문장이 단어 단위(토큰)로 분리됩니다.
      • 분석기를 설정하면 더 정교한 처리가 가능합니다.

      이렇게 생성된 토큰은 Inverted Index(역색인)에 저장됩니다.
      즉, Elasticsearch는 문장을 통째로 저장하는 것이 아니라, 토큰을 기반으로 색인을 생성하여 검색 성능을 높입니다.

       



      🔹 2. 검색어 분석(Query Parsing & Analysis)

      사용자가 "검색 엔진"을 검색한다고 가정해 보겠습니다.

      GET my_index/_search
      {
        "query": {
          "match": {
            "content": "검색 엔진"
          }
        }
      }
      

      📌 검색어 분석 과정

      1. 검색어를 토큰화 → "검색 엔진" → [ "검색", "엔진" ]
      2. 토큰을 Inverted Index에서 검색
      3. 가장 관련성이 높은 문서를 반환

      즉, 저장된 문서와 사용자의 검색어를 동일한 방식으로 분석하여 비교합니다.

       



      🔹 3. 역색인(Inverted Index) 조회

      Elasticsearch는 **역색인(Inverted Index)**을 사용하여 검색을 최적화합니다.

      📌 역색인이란?
      일반적으로 데이터베이스는 "문서 → 내용" 형태로 저장되지만,
      Elasticsearch는 "단어 → 문서 ID" 형태로 저장합니다.

      예를 들어, 다음과 같은 3개의 문서가 있다고 가정해 보겠습니다.

      문서 ID 내용
      1 "엘라스틱서치는 강력한 검색 엔진입니다."
      2 "검색 엔진을 사용하면 빠르게 검색할 수 있습니다."
      3 "AI 기반 검색 기술이 발전하고 있습니다."

      📌 Elasticsearch의 역색인 구조

      검색    → [1, 2, 3]  (문서 1, 2, 3에 존재)
      엔진    → [1, 2]    (문서 1, 2에 존재)
      강력한  → [1]       (문서 1에만 존재)
      

      검색어에 해당하는 문서 ID를 빠르게 찾을 수 있습니다.
      ➡ SQL 데이터베이스처럼 전체 데이터를 검색할 필요 없이, 색인된 데이터를 바로 조회할 수 있습니다.

       


       

      🔹 4. 검색 결과 정렬(Scoring & Ranking)

      Elasticsearch는 검색된 문서들의 유사도를 계산하여 정렬합니다.
      이를 위해 TF-IDF (Term Frequency - Inverse Document Frequency) 또는 BM25 알고리즘을 사용합니다.

      📌 TF-IDF 방식

      • TF(Term Frequency) → 특정 단어가 문서에서 얼마나 자주 등장하는가?
      • IDF(Inverse Document Frequency) → 해당 단어가 전체 문서에서 얼마나 희귀한가?

      📌 BM25 방식 (기본 알고리즘)

      • TF-IDF보다 더 정교한 방식으로, 검색어의 빈도와 문서 길이를 고려하여 가중치를 계산합니다.
      • Elasticsearch에서는 BM25가 기본 검색 스코어링 알고리즘입니다.

      즉, 가장 연관성이 높은 문서를 최상위에 배치하여 검색 결과를 반환합니다.

       


       

      🔹 5. 검색 결과 반환

      최종적으로 사용자가 검색한 "검색 엔진"에 대해 가장 관련성이 높은 문서부터 정렬하여 반환됩니다.

      📌 예제: 검색 결과

      {
        "hits": {
          "total": 3,
          "hits": [
            {
              "_id": "2",
              "_score": 1.8,
              "_source": { "content": "검색 엔진을 사용하면 빠르게 검색할 수 있습니다." }
            },
            {
              "_id": "1",
              "_score": 1.5,
              "_source": { "content": "엘라스틱서치는 강력한 검색 엔진입니다." }
            }
          ]
        }
      }
      

      문서 2가 문서 1보다 높은 점수를 받아 우선적으로 반환됨
      검색어와 가장 유사한 문서가 상위에 위치


      ✅ Elasticsearch Full-Text Search 요약

      단계 설명
      1. 문서 저장 (Indexing) 문장을 토큰화하여 Inverted Index 생성
      2. 검색어 분석 (Query Parsing) 사용자의 검색어도 동일한 방식으로 토큰화
      3. 역색인(Inverted Index) 조회 토큰을 기반으로 관련 문서를 빠르게 찾음
      4. 검색 결과 정렬 (Scoring & Ranking) BM25 알고리즘으로 관련성이 높은 문서 정렬
      5. 검색 결과 반환 가장 관련성이 높은 문서를 우선 반환

      즉, Elasticsearch는 저장과 검색 과정에서 토큰화 및 분석을 수행하며, 역색인을 통해 빠르고 정확한 검색을 제공합니다. 🚀

  2. ⚡ 빠른 검색 성능
    • Inverted Index 구조를 사용하여 대량의 데이터를 빠르게 검색
    • 검색어 자동 완성(Completion Suggester)과 유사어 검색 기능 제공
    • 수백만 개 이상의 문서도 짧은 시간 내에 검색 가능
      더보기
      더보기
      더보기
      더보기

      🔥 Elasticsearch의 빠른 검색 성능 구조

      Elasticsearch는 일반적인 데이터베이스(SQL)와 달리, Inverted Index(역색인)와 분산 검색을 활용하여 대량의 데이터를 빠르게 검색할 수 있습니다.
      이제, Elasticsearch의 검색 성능을 높이는 핵심 구조에 대해 세부적으로 설명하겠습니다.


      🔹 Elasticsearch가 빠른 이유

      Elasticsearch의 빠른 검색 성능을 가능하게 하는 주요 기술은 다음과 같습니다.

      1️⃣ 역색인(Inverted Index) 사용
      2️⃣ 분산 아키텍처(Shard & Replica) 적용
      3️⃣ 캐싱(Caching) 활용
      4️⃣ 압축된 데이터 저장 방식 활용
      5️⃣ 비동기식 검색(Asynchronous Query Execution)
      6️⃣ 쿼리 최적화(Query Optimization) 기능 제공


      🔍 1️⃣ 역색인(Inverted Index) 구조

      SQL 데이터베이스는 **정방향 색인(Forward Index)**을 사용하여 데이터를 저장하고 검색할 때, 문장을 통째로 비교해야 합니다.
      반면, Elasticsearch는 **역색인(Inverted Index)**을 활용하여 검색 속도를 획기적으로 개선합니다.

      📌 역색인이란?

      • 일반적인 데이터 저장 방식→ SQL에서는 데이터를 그대로 저장하고 검색 시 전체 데이터를 스캔해야 합니다.
      • 문서 1: "검색 엔진은 빠르게 데이터를 처리합니다." 문서 2: "빠른 검색이 필요할 때 엘라스틱서치를 사용합니다."
      • Elasticsearch의 역색인 방식→ Elasticsearch는 토큰 단위로 색인을 생성하여, 검색 시 해당 단어가 포함된 문서 ID를 바로 찾을 수 있도록 저장합니다.
      • "검색" → [문서 1, 문서 2] "엔진" → [문서 1] "빠르게" → [문서 1] "필요할" → [문서 2] "엘라스틱서치" → [문서 2]

      📌 역색인이 검색 속도를 빠르게 만드는 이유

      ✅ 단순 문자열 비교(SQL) 방식보다 훨씬 빠르게 일치하는 문서를 찾을 수 있음
      ✅ 특정 단어가 포함된 문서 목록을 바로 가져올 수 있어 전체 데이터 스캔을 하지 않아도 됨
      대용량 데이터에서도 성능 저하 없이 빠르게 검색 가능

       


       

      🗂 2️⃣ 분산 아키텍처(Sharding & Replication)

      Elasticsearch는 데이터를 여러 개의 노드(서버)로 분산하여 저장하고 검색 속도를 향상시킵니다.

      📌 샤딩(Sharding)

      샤드(Shard)는 하나의 인덱스를 여러 개로 나누어 저장하는 기술입니다.
      Elasticsearch는 각 샤드가 독립적인 검색 엔진 역할을 하도록 설계되어 있어, 검색 요청이 여러 개의 샤드에서 동시에 수행됩니다.

      샤드 개수 설정 (예제):

      PUT my_index
      {
        "settings": {
          "number_of_shards": 3,
          "number_of_replicas": 1
        }
      }
      
      • number_of_shards: 3 → 데이터를 3개 샤드로 나눠 저장
      • number_of_replicas: 1 → 백업을 위해 각 샤드의 복제본 1개 유지

      📌 샤딩이 빠른 검색을 가능하게 하는 이유 ✅ 여러 개의 샤드에서 동시에 검색을 수행하므로 검색 속도가 병렬적으로 증가
      ✅ 특정 샤드에서만 검색이 이루어지므로 불필요한 데이터 조회가 줄어듦

      📌 복제본(Replica)

      샤드의 복제본(Replica Shard)을 생성하면 검색 요청을 여러 개의 노드에서 동시에 처리할 수 있어 속도가 향상됩니다.

      복제본이 빠른 검색을 가능하게 하는 이유 ✅ 여러 개의 서버에서 동시에 검색 요청을 처리하여 부하를 분산
      ✅ 하나의 노드가 장애가 발생해도 검색 속도를 유지

       


       

      💾 3️⃣ 캐싱(Caching) 활용

      Elasticsearch는 자주 검색되는 쿼리를 캐싱하여 검색 속도를 최적화합니다.

      📌 검색 결과 캐싱(Query Cache)

      • terms, match와 같은 특정 쿼리를 실행하면, 동일한 쿼리에 대해 결과를 메모리에 저장합니다.
      • 다음 번 동일한 검색 요청이 들어오면 데이터를 다시 계산하지 않고 바로 결과를 반환합니다.

      캐시 설정 (예제):

      GET my_index/_search
      {
        "query": {
          "match": { "content": "검색 엔진" }
        },
        "request_cache": true
      }
      

      이후 동일한 검색 요청이 들어오면 캐시에서 즉시 결과를 반환하여 속도가 빨라집니다.

       


       

      🗜 4️⃣ 압축된 데이터 저장 방식 활용

      Elasticsearch는 색인을 저장할 때, 압축 알고리즘을 적용하여 데이터를 최적화합니다.

      LZ4 압축 알고리즘 사용

      • 데이터를 압축하여 저장함으로써 검색할 때 불필요한 IO 연산을 줄여 검색 속도를 향상합니다.

      Disk-Based Search 최적화

      • 데이터가 메모리에 적재되지 않아도 디스크에서 빠르게 검색 가능합니다.

       


       

      ⚡ 5️⃣ 비동기식 검색(Asynchronous Query Execution)

      Elasticsearch는 검색 요청을 처리할 때, 비동기적으로 실행하여 빠른 응답을 제공합니다.

      즉시 결과 반환(Async Search)

      • 사용자가 대량의 데이터를 검색하더라도 즉시 부분 결과를 반환하여 사용자 경험을 개선합니다.

      백그라운드 실행

      • 대용량 데이터 분석(Aggregation) 쿼리는 백그라운드에서 실행되어 속도를 최적화합니다.

       


       

      🎯 6️⃣ 쿼리 최적화(Query Optimization)

      Elasticsearch는 다음과 같은 최적화 기법을 사용하여 검색 성능을 높입니다.

      Query Rewriting (쿼리 재작성)

      • 불필요한 조건을 제거하여 쿼리 실행 속도를 최적화합니다.

      Lazy Evaluation (지연 실행)

      • 검색 조건을 분석하여 필요한 조건만 평가하여 실행합니다.

      Parallel Execution (병렬 실행)

      • 여러 개의 CPU 코어를 활용하여 쿼리를 병렬로 실행하여 검색 속도를 향상시킵니다.

       


       

      ✅ Elasticsearch의 빠른 검색 성능 요약

      검색 최적화 기술 설명
      역색인(Inverted Index) 검색어가 포함된 문서 목록을 빠르게 조회
      샤딩(Sharding) 데이터를 여러 개의 샤드로 나누어 저장하여 병렬 검색 수행
      복제본(Replica) 복제 샤드를 활용하여 검색 부하를 분산
      검색 결과 캐싱(Query Cache) 동일한 쿼리에 대해 메모리에 캐시하여 즉시 응답
      압축 저장 방식 데이터 크기를 줄여 디스크 IO 성능 최적화
      비동기식 검색(Async Search) 백그라운드에서 실행하여 즉시 응답 제공
      쿼리 최적화(Query Optimization) 불필요한 조건을 제거하고 병렬로 실행

      📌 결론:
      Elasticsearch는 역색인, 샤딩, 캐싱, 비동기 검색, 데이터 압축 등을 통해 초고속 검색을 지원합니다. 🚀
      이러한 기술 덕분에 Elasticsearch는 수십억 개의 데이터를 검색하더라도 빠른 성능을 유지할 수 있습니다.

  3. 📊 실시간 데이터 분석 (Aggregation Query)
    • 데이터 그룹화 및 통계 분석 가능
    • 인기 검색어 조회, 트렌드 분석, 사용자 행동 분석 등에 활용
    • terms aggregation, date histogram 등을 통해 다양한 데이터 집계 가능
      더보기
      더보기
      더보기
      더보기

      📊 Elasticsearch의 실시간 데이터 분석 수행 방식

      Elasticsearch는 단순한 검색 엔진이 아니라 실시간 데이터 분석을 수행하는 강력한 도구입니다.
      이 기능을 가능하게 하는 핵심 기술은 다음과 같습니다.


      🔹 실시간 데이터 분석을 위한 핵심 기술

      1. 실시간 데이터 수집 (Logstash, Beats, Kafka 연동)
      2. 색인(Indexing) 및 저장 방식 (Near Real-Time Processing)
      3. 집계(Aggregation) 쿼리를 통한 데이터 분석
      4. 시계열 분석(Time-Series Analysis)
      5. Kibana를 활용한 시각화
      6. 대용량 데이터 최적화(Query Optimization & Scaling)

      이제, 각각의 기술을 자세히 설명하겠습니다.

       


       

      1️⃣ 실시간 데이터 수집 (Logstash, Beats, Kafka 연동)

      Elasticsearch는 외부 데이터 소스로부터 데이터를 실시간으로 수집하여 분석할 수 있습니다.

      📌 실시간 데이터 수집 도구

      도구 설명
      Logstash 로그 및 다양한 데이터 소스를 수집하여 Elasticsearch에 전달
      Beats 경량 데이터 수집 에이전트 (파일 로그, 시스템 메트릭, 네트워크 데이터)
      Kafka 실시간 스트리밍 데이터를 Elasticsearch와 연동

      예제: Logstash로 MySQL 데이터를 실시간 전송

      input {
        jdbc {
          jdbc_connection_string => "jdbc:mysql://your-db-host:3306/db_name"
          jdbc_user => "user"
          jdbc_password => "password"
          statement => "SELECT * FROM transactions WHERE updated_at > NOW() - INTERVAL 1 MINUTE"
          schedule => "* * * * *" # 매 분마다 데이터 수집
        }
      }
      output {
        elasticsearch {
          hosts => ["http://localhost:9200"]
          index => "transactions"
        }
      }
      

      ➡ MySQL의 transactions 테이블 데이터를 1분마다 Elasticsearch로 전송하여 실시간 분석 가능

       


       

      2️⃣ 색인(Indexing) 및 저장 방식 (Near Real-Time Processing)

      Elasticsearch는 데이터를 저장할 때, Near Real-Time(NRT, 준실시간) 방식을 사용합니다.

      📌 색인 과정 (Indexing Process)

      1. 데이터 입력 → translog(트랜잭션 로그)에 저장
      2. 메모리에 저장된 후, Background Refresh로 Lucene Segment에 색인
      3. 1초마다 자동으로 Segment를 Refresh하여 검색 가능 상태로 변환

      실시간 분석이 가능한 이유
      ✅ 1초마다 데이터가 갱신되므로 거의 실시간으로 검색 가능
      ✅ 새로운 데이터가 들어와도 시스템 성능에 영향을 주지 않음

      색인 최적화 예제 (자동 Refresh 설정)

      PUT transactions/_settings
      {
        "index": {
          "refresh_interval": "1s"
        }
      }
      

      데이터가 들어오면 1초마다 검색할 수 있도록 반영

       


       

      3️⃣ 집계(Aggregation) 쿼리를 통한 데이터 분석

      Elasticsearch는 Aggregation Query를 사용하여 실시간 데이터 분석을 수행합니다.

      📌 집계(Aggregation)란?

      집계(Aggregation)란 데이터를 그룹화하고 통계를 계산하는 기능입니다.
      이를 활용하면 실시간으로 대량의 데이터를 분석하고 패턴을 찾을 수 있습니다.

      ✔ 예제 1: 실시간 거래 통계 분석 (평균 결제 금액)

      GET transactions/_search
      {
        "size": 0,
        "aggs": {
          "avg_price": {
            "avg": { "field": "price" }
          }
        }
      }
      

      실시간으로 평균 결제 금액을 계산하여 분석

      ✔ 예제 2: 시간별 거래 건수 집계 (1시간 단위)

      GET transactions/_search
      {
        "size": 0,
        "aggs": {
          "transactions_per_hour": {
            "date_histogram": {
              "field": "timestamp",
              "calendar_interval": "1h"
            }
          }
        }
      }
      

      1시간 단위로 거래량 변화를 실시간 분석

       


       

      4️⃣ 시계열 분석(Time-Series Analysis)

      Elasticsearch는 시계열 데이터 분석을 최적화하여 실시간으로 데이터를 분석할 수 있습니다.

      📌 시계열 분석이란?

      • 시간 기반 데이터를 수집하고, 트렌드 변화나 이상 탐지를 수행하는 기법
      • 주로 로그 분석, 네트워크 모니터링, 금융 데이터 분석 등에 활용

      ✔ 예제 1: 최근 1시간 동안의 CPU 사용률 분석

      GET system_metrics/_search
      {
        "size": 0,
        "query": {
          "range": {
            "timestamp": {
              "gte": "now-1h/h",
              "lte": "now/h"
            }
          }
        },
        "aggs": {
          "avg_cpu": {
            "avg": { "field": "cpu_usage" }
          }
        }
      }
      

      최근 1시간 동안의 CPU 평균 사용량을 실시간 분석

      ✔ 예제 2: 이상 감지(Anomaly Detection)

      GET website_traffic/_search
      {
        "size": 0,
        "aggs": {
          "unusual_spikes": {
            "percentiles": {
              "field": "request_count",
              "percents": [95, 99]
            }
          }
        }
      }
      

      트래픽이 급증하는 패턴을 실시간으로 감지하여 알림 설정 가능

       


       

      5️⃣ Kibana를 활용한 데이터 시각화

      Elasticsearch는 Kibana와 연동하여 데이터를 실시간으로 시각화할 수 있습니다.

      📌 Kibana 활용 예시

      ✅ 실시간 대시보드(Dashboard) 생성
      ✅ 시간별, 날짜별 데이터 트렌드 분석
      ✅ 사용자 이벤트 로그, 거래 데이터 등을 그래프 형태로 시각화

      예제: Kibana에서 실시간 검색어 트렌드 대시보드 생성

      1. search_logs 인덱스를 생성하고, keyword 필드를 분석
      2. Kibana의 Date Histogram을 이용하여 실시간 검색 트렌드 그래프 생성
      3.  

       

      6️⃣ 대용량 데이터 최적화(Query Optimization & Scaling)

      대용량 데이터를 실시간으로 분석하려면 성능 최적화가 필요합니다.

      📌 Elasticsearch 실시간 분석 최적화 전략

      최적화 방법 설명
      Shard 크기 조절 데이터를 적절한 크기로 분산 저장하여 검색 성능 향상
      Replica 증가 다중 노드에서 검색을 수행하여 부하 분산
      Query Cache 활용 동일한 분석 요청에 대해 캐싱하여 처리 속도 개선
      Refresh Interval 조정 분석에 따라 데이터 업데이트 속도 조절 (e.g., 1s → 10s)

      예제: 실시간 분석을 위한 인덱스 설정 최적화

      PUT transactions/_settings
      {
        "index": {
          "refresh_interval": "5s",
          "number_of_shards": 3,
          "number_of_replicas": 2
        }
      }
      

      데이터 갱신 주기를 5초로 설정하여 성능 최적화
      샤드와 복제본을 조정하여 대규모 실시간 데이터 분석 지원


      Elasticsearch 실시간 데이터 분석 요약

      기술 설명
      실시간 데이터 수집 Logstash, Beats, Kafka 연동
      Near Real-Time 색인 1초마다 자동 색인 갱신
      Aggregation 쿼리 실시간 데이터 그룹화 및 통계 분석
      시계열 분석 시간 기반 데이터 트렌드 분석
      Kibana 시각화 실시간 데이터 대시보드 생성
      최적화 기법 샤드 조정, 캐싱, Replica 증가

      📌 결론: Elasticsearch는 대량의 데이터를 실시간으로 수집, 색인, 분석하여 빠르고 효율적인 데이터 분석을 지원합니다. 🚀

  4. 💾 확장 가능한 분산 저장 구조
    • 데이터가 증가하면 자동으로 여러 노드에 분산 저장
    • 클러스터링을 통해 서버를 확장하고 부하 분산 가능
      더보기
      더보기
      더보기
      더보기

      Elasticsearch의 확장 가능한 분산 저장 구조 (Scalable Distributed Storage)

      Elasticsearch는 분산(Distributed) 구조를 기반으로 동작하며, 대량의 데이터를 효율적으로 저장하고 빠르게 검색할 수 있도록 확장 가능한 구조를 가지고 있습니다.

       


       

      🔹 Elasticsearch의 분산 저장 핵심 요소

      1. 샤드(Shard) 구조
      2. 복제본(Replica) 관리
      3. 클러스터(Cluster) 및 노드(Node) 구성
      4. 자동 데이터 재분배(Auto Rebalancing)
      5. 수평 확장(Scaling) 방식
      6. 고가용성(High Availability) 보장
      7. 노드 장애 처리(Fault Tolerance)

       


       

      🔹 1. 샤드(Shard) 구조

      Elasticsearch는 데이터를 **샤드(Shard)**라고 하는 작은 단위로 나누어 저장합니다.
      각 샤드는 독립적인 검색 엔진 역할을 수행하며, 여러 개의 노드에 분산될 수 있습니다.

      📌 샤드 개념

      • 샤드는 하나의 인덱스를 여러 개로 나누어 저장하는 데이터 조각입니다.
      • 각 샤드는 독립적인 Lucene 인덱스로 동작하며, 병렬 검색을 수행하여 속도를 높입니다.

      샤드 개수 설정 예제

      PUT my_index
      {
        "settings": {
          "number_of_shards": 3,
          "number_of_replicas": 1
        }
      }
      
      • number_of_shards: 3 → 인덱스를 3개의 샤드로 분할
      • number_of_replicas: 1 → 각 샤드의 복제본을 1개 유지

      샤드가 확장 가능한 이유여러 개의 샤드에서 병렬로 검색을 수행하여 속도를 높임
      샤드를 여러 개의 노드에 분산하여 스케일 아웃(Scale-Out) 가능
      샤드 단위로 확장하여 데이터를 효과적으로 저장

       


       

      🔹 2. 복제본(Replica) 관리

      복제본(Replica)은 샤드의 복사본으로, **고가용성(HA, High Availability) 및 부하 분산(Load Balancing)**을 위한 역할을 합니다.

      복제본의 역할

      • 검색 요청을 여러 노드에서 병렬 처리하여 검색 성능을 향상
      • 노드 장애 시, 복제본을 사용하여 데이터 유실 없이 복구
      • 부하를 분산하여 검색 속도를 높임

      복제본 개수 설정 예제

      PUT my_index/_settings
      {
        "index": {
          "number_of_replicas": 2
        }
      }
      
      • number_of_replicas: 2 → 각 샤드의 복제본을 2개 생성하여 고가용성을 확보

       


       

      🔹 3. 클러스터(Cluster) 및 노드(Node) 구성

      Elasticsearch는 클러스터(Cluster) 단위로 동작하며, 하나의 클러스터는 여러 개의 **노드(Node)**로 구성됩니다.

      클러스터 구조

      [ 클러스터 (Cluster) ]
          ├── 노드 1 (Master + Data Node) → 샤드 1, 샤드 2
          ├── 노드 2 (Data Node) → 샤드 3, 샤드 4
          ├── 노드 3 (Data Node) → 샤드 5, 샤드 6
          ├── 노드 4 (Coordinating Node)
      

      노드(Node) 역할

      노드 종류 역할
      Master Node 클러스터 관리, 샤드 배치 및 상태 모니터링
      Data Node 데이터를 저장하고 검색 쿼리 수행
      Coordinating Node 검색 요청을 분산하여 처리 속도 향상
      Ingest Node 데이터 변환 및 사전 처리 수행

      클러스터 확장 방식새로운 노드를 추가하면 자동으로 데이터가 분산
      노드 장애가 발생해도 복제본이 있기 때문에 데이터 유실 방지

       


       

      🔹 4. 자동 데이터 재분배(Auto Rebalancing)

      Elasticsearch는 클러스터 내에서 노드 추가/삭제 시 자동으로 데이터를 재분배합니다.

      노드 추가 시 데이터 자동 재분배

      • 새로운 노드가 추가되면, Elasticsearch는 자동으로 샤드를 분배하여 부하를 균등하게 조정합니다.
      • 예제: 노드 2개 → 3개로 확장하면, 기존 샤드가 새로운 노드로 자동 이동합니다.

      노드 장애 발생 시 데이터 자동 복구

      • 특정 노드가 다운되면, 복제본을 활성화하여 즉시 복구됩니다.

       


       

      🔹 5. 수평 확장(Scaling) 방식

      Elasticsearch는 **Scale-Out 방식(수평 확장)**을 지원하여, 데이터가 증가하더라도 노드를 추가하여 확장할 수 있습니다.

      Scale-Out vs Scale-Up

      확장 방식 설명
      Scale-Out 노드를 추가하여 클러스터를 확장 (Elasticsearch 방식)
      Scale-Up 기존 노드의 성능을 향상 (CPU, RAM 증가)

      Scale-Out 방식의 장점노드 추가만으로 무제한 확장 가능
      데이터 증가에도 성능 저하 없이 확장 가능
      클러스터가 자동으로 샤드를 분산하여 관리 부담 최소화

       


       

      🔹 6. 고가용성(High Availability) 보장

      Elasticsearch는 노드 장애가 발생해도 데이터가 손실되지 않도록 복제본을 관리하여 항상 가용성을 유지합니다.

      장애 발생 시 동작 방식

      1. 기본 데이터 샤드가 있는 노드가 장애 발생
      2. 복제본이 자동으로 새로운 기본 데이터 샤드로 승격 (Failover 발생)
      3. 새로운 복제본이 자동 생성되어 클러스터 안정성 유지

       


       

      🔹 7. 노드 장애 처리(Fault Tolerance)

      Elasticsearch는 노드 장애를 자동 감지하고 데이터 복구를 수행합니다.

      노드 장애 감지 & 복구 예제

      GET _cluster/health
      

      📌 출력 예제

      {
        "status": "yellow",   // 일부 샤드가 복제되지 않은 상태 (일부 장애)
        "unassigned_shards": 2
      }
      
      • status: green → 정상
      • status: yellow → 일부 샤드가 복제되지 않음
      • status: red → 일부 데이터가 손실됨 (긴급 조치 필요)

      장애 처리 방식

      • 장애 발생 시, 복제본을 새로운 데이터 샤드로 전환하여 Failover 처리
      • 새로운 노드가 추가되면, 샤드가 자동으로 이동하여 복구

       


       

      ✅ Elasticsearch 분산 저장 구조 요약

      기능 설명
      샤드(Shard) 구조 데이터를 여러 개로 분할하여 저장
      복제본(Replica) 관리 데이터 유실 방지 및 검색 부하 분산
      클러스터(Cluster) 및 노드(Node) 구성 여러 개의 노드로 데이터 분산
      자동 데이터 재분배(Auto Rebalancing) 노드 추가/삭제 시 자동으로 데이터 재분배
      수평 확장(Scaling) 노드 추가만으로 데이터 무제한 확장 가능
      고가용성(High Availability) 장애 발생 시 복제본을 사용하여 데이터 복구
      노드 장애 처리(Fault Tolerance) 노드 장애 감지 및 자동 복구

      📌 결론:
      Elasticsearch는 샤드, 복제본, 자동 분산, 클러스터 확장을 통해 데이터 증가에도 무제한 확장이 가능합니다.
      노드 장애 발생 시 자동 복구 및 Failover 기능을 제공하여 데이터 손실 없이 안정적으로 운영할 수 있습니다. 🚀

  5. 🔗 다양한 시스템과 연동 가능
    • MySQL, PostgreSQL, Kafka, Redis 등과 쉽게 연동
    • Kibana를 이용한 데이터 시각화 가능
    • Logstash, Beats 등의 데이터 수집 도구와 함께 사용 가능
      더보기
      더보기
      더보기
      더보기

      🔗 Elasticsearch의 다양한 시스템 연동 방식

      Elasticsearch는 강력한 RESTful API 기반의 설계 덕분에 다양한 시스템과 쉽게 연동할 수 있습니다.
      데이터 수집, 변환, 저장, 분석, 시각화를 위해 여러 도구와 통합할 수 있습니다.


      🔹 다양한 시스템과 연동을 위한 핵심 기술

      1. RESTful API 기반의 연동
      2. 데이터 수집 도구(Logstash, Beats, Kafka)
      3. 데이터베이스(MySQL, PostgreSQL) 연동
      4. 애플리케이션(Spring Boot, Python) 연동
      5. 대시보드 및 시각화(Kibana, Grafana)
      6. 메시징 시스템(Kafka, RabbitMQ) 연동
      7. 클라우드 서비스(AWS, GCP, Azure) 연동
      8. 보안 및 인증(OAuth, API Key, X-Pack)



      1️⃣ RESTful API 기반의 연동

      Elasticsearch는 RESTful API를 제공하며, 다양한 프로그래밍 언어와 쉽게 통합할 수 있습니다.

      데이터 저장 API (Indexing)

      POST http://localhost:9200/my_index/_doc/1
      Content-Type: application/json
      
      {
        "name": "Elasticsearch 연동 예제",
        "type": "데이터 저장"
      }
      

      데이터 검색 API (Query)

      GET http://localhost:9200/my_index/_search
      Content-Type: application/json
      
      {
        "query": {
          "match": { "name": "Elasticsearch" }
        }
      }
      

      Elasticsearch는 REST API를 통해 데이터를 저장, 검색, 삭제, 업데이트할 수 있으며, 다양한 시스템과 연동이 가능합니다.



      2️⃣ 데이터 수집 도구 연동 (Logstash, Beats, Kafka)

      Elasticsearch는 로그 데이터, 이벤트 스트리밍, 시스템 메트릭 등을 수집하는 여러 도구와 연동할 수 있습니다.

      📌 Logstash 연동

      Logstash는 다양한 데이터 소스(MySQL, 파일, Kafka 등)에서 데이터를 수집하여 변환 후 Elasticsearch로 저장할 수 있습니다.

      Logstash 설정 예제 (MySQL → Elasticsearch)

      input {
        jdbc {
          jdbc_connection_string => "jdbc:mysql://db_host:3306/mydb"
          jdbc_user => "user"
          jdbc_password => "password"
          statement => "SELECT * FROM users"
          schedule => "* * * * *" # 매 분마다 실행
        }
      }
      output {
        elasticsearch {
          hosts => ["http://localhost:9200"]
          index => "users_index"
        }
      }
      

      MySQL 데이터를 실시간으로 Elasticsearch에 저장 가능

      📌 Beats 연동

      Beats는 경량 데이터 수집 에이전트로, 시스템 로그, 네트워크 트래픽 등을 수집하여 Elasticsearch로 전송할 수 있습니다.

      Filebeat 설정 예제 (로그 파일 → Elasticsearch)

      filebeat.inputs:
        - type: log
          paths:
            - /var/log/*.log
      output.elasticsearch:
        hosts: ["http://localhost:9200"]
      

      Filebeat를 사용하면 서버 로그 파일을 실시간으로 Elasticsearch로 전송 가능



      3️⃣ 데이터베이스(MySQL, PostgreSQL) 연동

      Elasticsearch는 관계형 데이터베이스(RDBMS)와 연동하여 데이터를 실시간으로 검색 및 분석할 수 있습니다.

      MySQL → Elasticsearch 데이터 동기화

      • Logstash + JDBC 플러그인을 사용하여 MySQL 데이터를 주기적으로 Elasticsearch에 저장
      • Debezium을 사용하여 MySQL의 변경 사항을 Elasticsearch에 실시간 반영

      PostgreSQL → Elasticsearch 데이터 동기화

      • elasticsearch-jdbc 플러그인을 사용하여 PostgreSQL 데이터를 동기화
      • Kafka Connect를 활용하여 PostgreSQL 데이터를 스트리밍 방식으로 전송



      4️⃣ 애플리케이션(Spring Boot, Python) 연동

      Elasticsearch는 Java, Python, Node.js 등 다양한 프로그래밍 언어와 연동할 수 있습니다.

      📌 Spring Boot 연동

      Spring Data Elasticsearch를 사용하여 Elasticsearch와 연동할 수 있습니다.

      Spring Boot 설정 (application.yml)

      spring.elasticsearch.uris: http://localhost:9200
      

      Elasticsearch Repository 생성

      import org.springframework.data.elasticsearch.repository.ElasticsearchRepository;
      
      public interface UserRepository extends ElasticsearchRepository<UserDocument, String> {
          List<UserDocument> findByUsername(String username);
      }
      

      검색 API

      @GetMapping("/search")
      public List<UserDocument> search(@RequestParam String username) {
          return userRepository.findByUsername(username);
      }
      

      Spring Boot 애플리케이션에서 Elasticsearch를 직접 검색할 수 있음



      5️⃣ 대시보드 및 시각화(Kibana, Grafana)

      Elasticsearch 데이터를 실시간으로 시각화하려면 Kibana 또는 Grafana를 사용합니다.

      📌 Kibana 연동

      kibana.yml 설정:
      server.port: 5601
      elasticsearch.hosts: ["http://localhost:9200"]
      

      Kibana를 사용하면 실시간 대시보드를 구성하여 데이터를 시각적으로 분석 가능



      6️⃣ 메시징 시스템(Kafka, RabbitMQ) 연동

      Elasticsearch는 Kafka 또는 RabbitMQ와 연동하여 실시간 데이터 스트리밍을 처리할 수 있습니다.

      📌 Kafka → Elasticsearch 데이터 연동

      Kafka Connect를 사용하여 Kafka의 메시지를 실시간으로 Elasticsearch에 저장할 수 있습니다.

      Kafka Connect 설정 (sink-connector.json)

      {
        "name": "elasticsearch-sink",
        "config": {
          "connector.class": "io.confluent.connect.elasticsearch.ElasticsearchSinkConnector",
          "topics": "user-logs",
          "connection.url": "http://localhost:9200",
          "type.name": "user_logs"
        }
      }
      

      Kafka 메시지를 Elasticsearch에 자동 저장하여 실시간 검색 가능



      7️⃣ 클라우드 서비스(AWS, GCP, Azure) 연동

      Elasticsearch는 클라우드 환경에서도 쉽게 배포 및 운영할 수 있습니다.

      📌 AWS OpenSearch Service 연동

      AWS OpenSearch Service는 Elasticsearch의 관리형 서비스입니다.

      AWS OpenSearch에 데이터 저장

      curl -X POST "https://search-my-domain.region.es.amazonaws.com/my_index/_doc" -H "Content-Type: application/json" -d'
      {
        "name": "AWS OpenSearch 연동 예제",
        "type": "클라우드"
      }'
      

      AWS, GCP, Azure에서도 Elasticsearch를 확장 가능



      8️⃣ 보안 및 인증(OAuth, API Key, X-Pack)

      Elasticsearch는 X-Pack, API Key, OAuth 인증을 지원하여 안전한 데이터 연동을 보장합니다.

      API Key 인증

      curl -X GET "http://localhost:9200/_cluster/health" -H "Authorization: ApiKey YOUR_API_KEY"
      

      X-Pack을 통한 Role-Based Access Control (RBAC)

      PUT _security/role/logs_reader
      {
        "indices": [
          { "names": ["logs-*"], "privileges": ["read"] }
        ]
      }
      

      보안을 강화하여 안전한 Elasticsearch 연동 가능



      Elasticsearch 연동 구조 요약

      연동 시스템 설명
      RESTful API Elasticsearch의 기본 인터페이스
      Logstash / Beats 실시간 로그 및 데이터 수집
      MySQL, PostgreSQL RDBMS 데이터 연동
      Spring Boot, Python 애플리케이션과 직접 연결
      Kibana, Grafana 데이터 시각화 및 분석
      Kafka, RabbitMQ 실시간 스트리밍 데이터 처리
      AWS, GCP, Azure 클라우드 환경 연동
      OAuth, API Key 보안 인증 및 접근 제어

      📌 결론:
      Elasticsearch는 RESTful API와 다양한 데이터 수집/처리 도구를 활용하여 다른 시스템과 쉽게 연동할 수 있습니다.
      실시간 로그 수집, 데이터베이스 동기화, 애플리케이션 연동, 메시징 시스템 연결까지 가능하여 확장성이 뛰어납니다. 🚀

결론

Elasticsearch의 핵심 기능은 대용량 데이터에 대한 빠른 검색과 실시간 데이터 분석입니다.

'Elastic Search > Elastic Stack' 카테고리의 다른 글

[Elasticsearch] Beats  (1) 2025.02.01
[Elasticsearch] Kibana  (0) 2025.02.01
[Elasticsearch] Logstash  (0) 2025.02.01
[Elasticsearch] Elasticsearch  (0) 2025.02.01
[Elasticsearch] 엘라스틱 서치란?  (0) 2025.02.01

GitHub Actions

📌 GitHub Actions는 GitHub에 내장된 CI/CD 도구로, 소스 코드 저장소 내에서 코드 테스트, 빌드, 배포 등의 작업을 자동화합니다. GitHub Actions는 별도의 CI/CD 서버 구축 없이 GitHub와 쉽게 통합되며, 사용자가 YAML 형식의 워크플로 파일을 통해 간단하게 자동화 작업을 설정할 수 있습니다.

 

주요 특징

  1. GitHub 통합: GitHub와 완벽히 통합되어, 저장소 내 이벤트(push, pull request 등)를 기반으로 자동화 실행.
  2. 서버리스: CI/CD 서버를 별도로 운영할 필요 없이 GitHub에서 바로 실행.
  3. 무료 제공 범위:
    • 스토리지: 500MB
    • 실행 시간: 월 2,000분 (무료 사용자 기준)
  4. YAML 기반 설정:
    • 워크플로는 반드시 .github/workflows 디렉토리에 저장.
    • YAML 파일을 작성해 자동화 작업 정의.

 

GitHub Actions의 CI (Continuous Integration)

개념

  • CI in GitHub Actions:
    • 코드 병합 시 자동 테스트 및 빌드를 실행.
    • 테스트 통과된 코드만 develop, main 브랜치로 병합되도록 설정.
    • 코드 품질 유지 및 안정적인 배포 보장.

활용 예시

  1. develop 브랜치에 병합 시:
    • gradle test 실행.
  2. feature/* 브랜치에 push 시:
    • 테스트 실행 후 알림(Slack, 이메일 등) 전송.

샘플 CI 워크플로

# 워크플로 이름을 설정 (GitHub Actions UI에서 표시됨)
name: CI

# 워크플로가 트리거되는 조건 정의
on:
  push: # push 이벤트 발생 시 실행
    branches: 
      - develop # develop 브랜치에 push되었을 때 실행
      - feature/** # feature 하위 브랜치에 push되었을 때 실행

# 작업(Job) 정의 시작
jobs:
  ci: # Job의 이름 정의
    runs-on: ubuntu-latest # 실행 환경으로 최신 버전의 Ubuntu를 사용

    # Job에서 실행할 작업 단계 정의
    steps:
      # 1. 리포지토리 코드를 체크아웃 (clone)
      - name: Checkout repository # 단계 이름
        uses: actions/checkout@v4 # GitHub Actions의 공식 체크아웃 액션 사용

      # 2. Java 환경 설정
      - name: Setup Java # 단계 이름
        uses: actions/setup-java@v3 # Java 설정을 위한 액션 사용
        with:
          java-version: '17' # Java의 버전을 17로 설정

      # 3. Gradle을 사용해 테스트 실행
      - name: Run Gradle tests # 단계 이름
        run: ./gradlew clean test # Gradle 명령어를 실행하여 테스트 수행

 

GitHub Actions의 CD (Continuous Deployment)

개념

  • CD in GitHub Actions:
    • main 브랜치에 병합된 코드를 자동으로 배포.
    • 배포 작업에 필요한 빌드, 테스트, 배포 프로세스를 YAML로 정의.

활용 예시

  1. main 브랜치에 병합 시:
    • 테스트 실행 후 JAR 파일 생성.
    • 생성된 JAR 파일을 AWS, GCP, Heroku 등으로 배포.

샘플 CD 워크플로

# 워크플로 이름을 설정
name: CD

# 워크플로 트리거 조건 설정
on:
  push: # push 이벤트 발생 시 실행
    branches: [ main ] # main 브랜치에 push되었을 때만 실행

# 작업(Job) 정의 시작
jobs:
  cd: # Job의 이름 정의
    runs-on: ubuntu-latest # 실행 환경으로 최신 버전의 Ubuntu를 사용

    # Job에서 실행할 작업 단계 정의
    steps:
      # 1. 리포지토리 코드 체크아웃
      - name: Checkout repository # 단계 이름
        uses: actions/checkout@v4 # GitHub Actions의 공식 체크아웃 액션 사용

      # 2. Java 환경 설정
      - name: Setup Java # 단계 이름
        uses: actions/setup-java@v3 # Java 설정을 위한 액션 사용
        with:
          java-version: '17' # Java의 버전을 17로 설정

      # 3. Gradle 테스트 실행
      - name: Run Gradle tests # 단계 이름
        run: ./gradlew clean test # Gradle 명령어를 실행하여 테스트 수행

      # 4. Heroku에 배포
      - name: Deploy to Heroku # 단계 이름
        uses: akhileshns/heroku-deploy@v3.12.12 # Heroku 배포를 위한 액션 사용
        with:
          heroku_api_key: ${{secrets.HEROKU_API_KEY}} # Heroku API 키를 GitHub Secrets에서 가져옴
          heroku_app_name: "sampleapp-github-actions" # Heroku 앱 이름 (고유해야 함)
          heroku_email: "user@example.com" # Heroku 계정 이메일

 

GitHub Actions의 장단점

  장점 단점
통합성 GitHub와 완벽히 통합되어 추가 도구 없이 자동화 가능. GitHub 플랫폼에 종속적.
사용 편의성 YAML 형식으로 간단히 워크플로 설정 가능. 복잡한 파이프라인 구성 시 설정 파일이 복잡해질 수 있음.
비용 효율성 무료 플랜으로 소규모 프로젝트에 적합. 대규모 프로젝트에서는 추가 비용 발생 가능.
확장성 다양한 오픈소스 액션 지원(GitHub Marketplace)으로 손쉬운 확장 가능. 커스텀 요구사항에 맞는 액션은 직접 작성해야 함.
자동화 수준 CI/CD 전 과정 자동화 가능. 실행 환경 제한(특정 OS/환경에서의 실행은 복잡).

 

GitHub Actions의 사용 이유

  1. 빠르고 간단한 설정: .github/workflows에 YAML 파일을 작성해 바로 사용 가능.
  2. GitHub와의 높은 호환성: Pull request, Push 등 GitHub 이벤트와 밀접하게 연동.
  3. 비용 절감: 무료 플랜으로 소규모 프로젝트에서 부담 없이 사용 가능.
  4. 강력한 커뮤니티와 확장성:
    • GitHub Marketplace에서 다양한 Actions 활용 가능.
    • DevOps 문화에 적합한 자동화 도구 제공.

 

정리

  GitHub Actions CI   GitHub Actions CD
목적 코드 변경 사항의 빌드 및 테스트 자동화 코드 변경 사항의 자동 배포
주요 작업 - Gradle, Maven 등 빌드 도구 테스트- 코드 품질 보장 - AWS, Heroku 등 클라우드 서비스로 배포
트리거 - Push- Pull Request - Main 브랜치로의 병합
사용 예시 - 브랜치별 테스트- 테스트 실패 시 알림 전송 - 빌드된 파일 배포- 프로덕션 환경 배포
필요 도구 Java, Gradle, Docker, Slack Heroku, AWS, Docker
장점 빠른 피드백, 품질 유지 배포 시간 단축, 자동화된 릴리스

 

부가적으로 알아야 할 정보

  1. GitHub Secrets:
    • API 키, 데이터베이스 비밀번호 등 민감한 정보를 안전하게 관리.
    • secrets.변수명으로 워크플로에서 참조 가능.
  2. GitHub Marketplace:
    • 다양한 오픈소스 액션 제공(테스트, 배포, 코드 분석 등).
    • 사용자가 만든 커스텀 액션을 공유하거나 활용 가능.
  3. 모니터링 및 디버깅:
    • GitHub Actions에서 제공하는 로그를 통해 워크플로 실행 과정을 모니터링 및 디버깅.

 

Github Actions 뜯어보기

  • Workflow
    • 최상위 개념
    • 여러 Job으로 구성되고, Event에 의해 트리거될 수 있는 자동화된 프로세스
    • Workflow 파일은 YAML으로 작성되고, Github Repository의 .github/workflows 폴더 아래에 저장됨
  • event
    • Github Repository에서 발생하는 push, pull request open, issue open, 특정 시간대 반복(cron) 등의 특정한 규칙
    • workflow 를 실행(trigger)함
  • runner
    • Github Action Runner app이 설치된 VM
    • Workflow가 실행될 instance로, 각각의 Job 들은 개별적인 runner에서 실행
  • job
    • 하나의 runner에서 실행될 여러 step의 모음을 의미
  • step
    • 실행 가능한 하나의 shell script 또는 action
  • Actions
    • Workflow의 가장 작은 단위로 재사용이 가능
    • Job을 만들기 위해 Step들을 연결
  • workflow 뜯어보기

  • with: plugin 에서 사용할 파라미터들
  • run: 실제로 실행할 스크립트

 

Github Actions 을 활용한 CI/CD 파이프라인 배포

  • 전체 흐름
    • 개발자는 feature/ 로 시작하는 브랜치를 만들어서 test코드를 포함한 수정 작업을 완료한 뒤 Pull Request 생성
    • (자동화) Pull Request를 만들면 해당 브랜치에 대해 gradle test를 수행
    • Pull Request 코드의 test가 실패한 경우, Pull Request 를 생성한 개발자는 test 코드를 수정하여 Pull Request를 변경
    • Pull Request 코드의 test가 성공한 경우, 다른 개발자들의 승인을 기다림
    • 다른 개발자들은 Pull Request의 코드를 승인하거나 댓글로 소통
    • (자동화) main 브랜치에 merge 되면 해당 브랜치를 cloudtype 서버에 배포

 

 

📌 

  •  

 

 

 

📌 

  •  

 

 

 

📌 

  •  

 

 

 

📌 

  •  

 

 

 

📌 

  •  

 

 

 

📌 

  •  

 

 

 

📌 

  •  

 

 

 

📌 

  •  

 

 

 

📌 

  •  

 

 

 

📌 

  •  

 

 

 

📌 

  •  

 

 

 

📌 

  •  

 

 

 

📌 

  •  

 

 

 

📌 

  •  

 

 


 

 

 🐳 

  •  

 

 

 

 🐳 

  •  

 

 

 

 🐳 

  •  

 

 


 

소제목 

🧩 부모 타입 변수 = 자식 타입 객체; 는 자동으로 부모 타입으로 변환이 일어납니다.

 


 

소제목 

🎵 클래스가 설계도라면 추상 클래스는 미완성된 설계도입니다.

'Docker > Docker' 카테고리의 다른 글

[Docker] Docker 모니터링&로깅  (0) 2025.02.04
[Docker] Docker Compose  (0) 2025.02.03
[Docker] Dockerfile  (1) 2025.02.01
[Docker] Docker+CI/CD  (0) 2025.01.30
[Docker] Docker 기초  (0) 2025.01.29

CI/CD

CI (Continuous Integration, 지속적 통합)

  • 개발자가 코드 변경 사항을 공유 저장소자주 병합하며, 이를 통해 변경 사항이 팀 내에서 빠르게 통합될 수 있도록 지원.
  • 핵심 구성 요소:
    • 자동화 빌드: 코드가 병합될 때마다 프로젝트가 자동으로 빌드됨.
    • 자동화 테스트: 빌드된 프로젝트에 대해 자동으로 테스트가 실행되어 오류나 결함을 조기에 발견.
    • 소스 코드 관리: GitHub, GitLab, Bitbucket 등의 저장소를 사용하여 팀원이 동일한 코드 베이스를 관리.

CD (Continuous Delivery/Deployment, 지속적 제공/배포)

  • Continuous Delivery (지속적 제공):
    • 모든 코드 변경 사항이 프로덕션 환경에 배포 가능한 상태로 자동 준비.
    • 배포 전, 수동 승인 과정을 포함하여 프로덕션 환경에서의 안전성을 보장.
  • Continuous Deployment (지속적 배포):
    • 코드 변경 사항이 자동으로 프로덕션 환경에 배포되며, 별도의 수동 승인 없이 진행.
    • 완전히 자동화된 배포 파이프라인을 통해 운영 비용을 절감.

CI/CD 주요 구성 요소

  1. 소스 코드 관리(SCM): Git을 사용하여 코드 버전을 관리하고 팀 협업을 지원.
  2. 빌드 자동화 도구: Jenkins, GitLab CI/CD, CircleCI, TravisCI 등.
  3. 테스트 자동화: 다양한 테스트(단위 테스트, 통합 테스트, E2E 테스트)를 자동 실행.
  4. 배포 자동화: Docker, Kubernetes와 같은 컨테이너 및 오케스트레이션 툴을 활용한 배포 관리.
  5. 모니터링 및 피드백: Prometheus, Grafana, ELK 스택 등을 사용하여 문제를 조기에 탐지.

CI/CD의 상세 장단점

  장점  단점
CI - 변경 사항에 대한 빠른 피드백
- 코드 품질 유지
- 병합 충돌 감소
- 자동화로 생산성 향상
- 설정 복잡 (빌드 서버, 테스트 환경 구축 필요)
- 테스트 커버리지 부족 시 문제 탐지 어려움
Continuous Delivery - 코드 배포 준비 시간 단축
- 안정적인 릴리스 프로세스 구축
- 수동 배포 시 위험 최소화
- 릴리스 승인 절차로 인해 배포 지연 가능
- 추가적인 테스트와 검증 단계가 필요
Continuous Deployment - 실시간 사용자 피드백 수집 가능
- 업데이트 빈도가 높아짐
- 운영비용 절감 및 시장 대응력 강화
- 초기 설정 및 유지보수 복잡
- 충분히 자동화된 테스트가 없을 경우 문제 발생 가능

CI/CD 사용 이유

  1. 품질 개선:
    • 코드 병합 시 자동으로 테스트를 수행해 결함을 사전에 발견.
    • 코드 리뷰 프로세스와 통합하여 개발 표준을 준수.
  2. 효율성 증가:
    • 반복적이고 수동적인 작업을 자동화하여 개발자 생산성 향상.
    • 릴리스 주기를 단축해 시간 및 인력 비용 절감.
  3. 리스크 감소:
    • 변경 사항이 점진적으로 배포되므로 대규모 릴리스로 인한 문제 발생 가능성 감소.
    • 롤백 자동화로 문제 발생 시 신속한 복구 가능.
  4. 팀 협업 강화:
    • 병합 시 충돌을 최소화하고, 투명한 코드 공유를 통해 팀 간 협력 향상.
    • DevOps 문화를 활성화하여 개발과 운영의 경계를 허물음.

CI/CD 프로세스 상세 표

  Continuous Integration  Continuous Delivery  Continuous Deployment
목적 코드 변경 사항 병합 후 자동 빌드 및 테스트 배포 준비 상태를 자동화 변경 사항을 자동으로 프로덕션에 배포
주요 활동 - 소스 코드 병합- 자동 빌드- 자동 테스트 - 자동화된 테스트- 릴리스 패키지 생성- 승인 대기 - 완전 자동화된 배포- 문제 시 자동 롤백
자동화 수준 테스트 및 빌드 자동화 테스트 및 배포 준비 자동화 완전 자동화
필요한 도구 Git, Jenkins, Maven, JUnit Ansible, Terraform, Docker Kubernetes, Helm, ArgoCD
적용 사례 소규모 프로젝트, 개발 단계 중간 규모 이상의 프로젝트 대규모 서비스, 빈번한 업데이트 환경

 

 

Docker+CI/CD

Docker와 CI/CD를 결합하면 개발, 테스트, 배포 프로세스를 표준화하고, 애플리케이션의 이식성과 안정성을 크게 향상할 수 있습니다. 


Docker와 CI/CD의 결합 개념

  • Docker: 컨테이너화를 통해 애플리케이션과 모든 종속성을 하나의 이미지로 패키징. 어떤 환경에서도 동일하게 동작하도록 보장.
  • CI/CD:
    • CI: Docker 이미지를 생성하고 테스트를 자동화.
    • CD: Docker 이미지를 사용해 스테이징 또는 프로덕션 환경에 배포.

Docker+CI/CD의 주요 장점

장점 내용
이식성 Docker 이미지를 사용하면 환경 차이에 상관없이 동일한 애플리케이션 동작을 보장.
일관성 유지 모든 개발, 테스트, 배포 환경에서 동일한 컨테이너 이미지를 사용하여 일관된 결과를 제공.
자동화된 워크플로우 CI/CD 파이프라인에서 Docker를 활용하여 빌드, 테스트, 배포 과정을 자동화.
신속한 배포 Docker 이미지를 미리 빌드하고 저장소(예: Docker Hub, AWS ECR)에 푸시하여 빠르게 배포 가능.
비용 절감 컨테이너를 사용해 경량화된 환경을 제공하고 리소스를 효율적으로 사용.

Docker와 CI/CD를 활용한 워크플로우

  1. 코드 작성 및 변경: 개발자가 소스 코드를 작성하고 Git 저장소에 커밋.
  2. Docker 이미지 생성:
    • CI 파이프라인에서 Dockerfile을 기반으로 이미지를 빌드.
    • 이미지에 필요한 애플리케이션 코드와 종속성을 포함.
  3. 자동화 테스트:
    • Docker 컨테이너에서 테스트 스크립트를 실행하여 애플리케이션의 동작 검증.
  4. 이미지 저장소 푸시:
    • 테스트를 통과한 Docker 이미지를 Docker Hub, AWS ECR, Azure ACR 등에 푸시.
  5. 배포 자동화:
    • CD 파이프라인에서 저장소에 있는 이미지를 스테이징 또는 프로덕션 환경에 배포.
    • Kubernetes 등 오케스트레이션 도구를 활용해 배포 관리.
  6. 모니터링 및 피드백:
    • 배포된 애플리케이션의 성능과 로그를 모니터링하고, 피드백 루프를 구축.

CI/CD 파이프라인에서 Docker 사용 사례

사용 사례 설명
빌드 자동화 Dockerfile을 사용해 CI 과정에서 표준화된 애플리케이션 이미지를 자동 생성.
테스트 환경 표준화 Docker 컨테이너를 활용하여 동일한 테스트 환경을 제공하고, 테스트의 일관성 보장.
멀티 서비스 배포 Docker Compose 또는 Kubernetes를 통해 여러 서비스를 동시에 컨테이너로 배포.
롤백 지원 문제가 있는 배포는 이전 버전의 Docker 이미지를 사용해 신속히 롤백 가능.
블루-그린 배포 및 카나리 배포 Docker를 활용하여 새로운 버전을 점진적으로 배포하거나 테스트 배포 가능.

Docker와 CI/CD를 구현하는 도구

도구  역할  설명
Jenkins CI/CD 자동화 도구 Docker 플러그인과 통합하여 이미지를 빌드하고 컨테이너에서 테스트 실행.
GitLab CI/CD GitLab의 내장 CI/CD 도구 Docker 이미지를 빌드하고, 스테이징 및 프로덕션 배포를 자동화.
CircleCI 클라우드 기반 CI/CD 서비스 Docker 이미지 생성 및 컨테이너 기반 테스트 지원.
Docker Hub Docker 이미지 저장소 Docker 이미지를 관리하고 배포 파이프라인에서 사용.
Kubernetes 컨테이너 오케스트레이션 도구 다수의 Docker 컨테이너를 관리하고, 스케일링 및 업데이트 수행.

간단한 예: GitLab CI/CD + Docker

1. Dockerfile 작성

# 베이스 이미지 설정
FROM node:14

# 작업 디렉토리 설정
WORKDIR /app

# 패키지 파일 복사 및 설치
COPY package*.json ./
RUN npm install

# 애플리케이션 코드 복사
COPY . .

# 애플리케이션 실행
CMD ["npm", "start"]

2. GitLab CI/CD 설정 (.gitlab-ci.yml)

stages:
  - build
  - test
  - deploy

build:
  stage: build
  image: docker:latest
  services:
    - docker:dind
  script:
    - docker build -t my-app .

test:
  stage: test
  image: docker:latest
  script:
    - docker run my-app npm test

deploy:
  stage: deploy
  image: docker:latest
  script:
    - docker tag my-app my-dockerhub-repo/my-app:latest
    - docker push my-dockerhub-repo/my-app:latest

 

'Docker > Docker' 카테고리의 다른 글

[Docker] Docker 모니터링&로깅  (0) 2025.02.04
[Docker] Docker Compose  (0) 2025.02.03
[Docker] Dockerfile  (1) 2025.02.01
[CI/CD] Github Actions CI  (0) 2025.01.31
[Docker] Docker 기초  (0) 2025.01.29

Docker의 장점

1. 애플리케이션 개발 및 배포의 간편화

  • 환경 격리:
    • Docker 컨테이너 내부에서 소프트웨어를 설치하고 실행하더라도, 호스트 OS에는 영향을 미치지 않습니다.
  • 일관성 있는 배포:
    • 동일한 환경에서 실행되는 컨테이너를 사용하여 개발, 테스트, 운영 환경 간에 일관성을 유지합니다.
  • CI/CD 지원:
    • 지속적인 통합(Continuous Integration) 및 배포(Continuous Deployment) 과정에서 Docker는 테스트 및 배포를 표준화합니다.

2. 독립성과 확장성 강화

  • 애플리케이션의 독립성:
    • 각 컨테이너는 독립적으로 실행되므로, 여러 애플리케이션이 서로 간섭 없이 동작할 수 있습니다.
  • 확장성:
    • 컨테이너 기반으로 손쉽게 애플리케이션을 스케일 업 또는 스케일 다운할 수 있습니다.

3. Docker의 표준화된 위치

  • 사실상 가상화의 표준:
    • Docker는 경량화된 컨테이너 기술로, 기존의 가상머신보다 빠르고 효율적입니다.
    • 다양한 클라우드 플랫폼에서 Docker를 지원하며, DevOps 환경에서 널리 사용됩니다.

 

Docker Image 관리

 

Docker 이미지란?

  • Docker 이미지는 **컨테이너 실행에 필요한 모든 요소(파일, 라이브러리, 설정 값 등)**를 포함한 가벼운 템플릿입니다.
  • Immutable(불변성):
    • 이미지가 한 번 생성되면 변경할 수 없으며, 수정이 필요하면 새로운 이미지를 생성해야 합니다.
  • Stateless(상태 저장 없음):
    • 컨테이너 실행 시 필요한 정적 파일만 포함하며, 데이터 상태는 컨테이너 외부 볼륨에 저장하거나 컨테이너 실행 중에만 유지됩니다.

Docker 이미지의 구조

Docker 이미지는 계층화된 파일 시스템으로 구성되며, 각 계층은 이미지의 변경 사항을 나타냅니다.

이미지 계층 구성

  1. Base Layer:
    • 모든 Docker 이미지는 베이스 이미지로부터 시작됩니다.
    • 예: ubuntu, alpine, node 등.
  2. Intermediate Layers:
    • 애플리케이션 실행에 필요한 파일, 라이브러리, 환경 설정 등이 추가된 계층.
    • 각 명령(RUN, COPY, ADD)이 실행될 때마다 새로운 계층이 생성됩니다.
  3. Top Layer:
    • 최종 애플리케이션 상태를 포함하는 계층.
    • 변경 사항 없이 불변으로 유지.

Docker 이미지 구조 확인

  1. 이미지 목록 확인
    • 설치된 모든 Docker 이미지를 확인.
  2. docker images
  3. 이미지 세부 정보 확인
    • 이미지의 메타데이터(환경 변수, 볼륨, 작업 디렉토리 등)를 확인.
  4. docker inspect <image-name-or-id>
  5. 이미지 계층 확인
    • 이미지가 어떻게 구성되었는지, 각 계층의 명령과 크기를 확인.
  6. docker history <image-name-or-id>

Docker 이미지의 장점

  1. 경량화:
    • 필요한 파일과 설정만 포함하여 용량이 작음.
    • 효율적인 저장 및 전송 가능.
  2. 이식성:
    • 동일한 이미지를 사용해 어떤 환경에서도 일관된 애플리케이션 실행 가능.
  3. 효율적인 업데이트:
    • 이미지를 수정할 필요가 있으면 새로운 계층만 생성.
    • 기존 계층은 캐시로 재사용 가능.

이미지 생성 및 관리

Dockerfile을 사용한 이미지 생성

# Base Layer
FROM ubuntu:latest

# Intermediate Layers
RUN apt-get update && apt-get install -y curl
COPY ./app /app
WORKDIR /app

# Top Layer
CMD ["./start.sh"]

이미지 빌드

docker build -t my-app:1.0 .

이미지 실행

docker run -it my-app:1.0

이미지 업데이트

  • 기존 이미지를 수정할 수 없으므로, 새로운 Dockerfile을 작성해 새 이미지를 생성해야 합니다.
  • 이미지를 업데이트하면 캐싱된 계층을 활용하여 빌드 속도를 개선.

요약

특징  설명
Stateless - 컨테이너 실행 시 상태 데이터를 유지하지 않음.- 애플리케이션 실행 환경을 동일하게 유지.
Immutable - 이미지 수정 불가.- 새로운 요구사항 발생 시 새로운 이미지를 생성해야 함.
구성 방식 - 계층화된 파일 시스템.- 각 명령(RUN, COPY)이 실행될 때마다 계층 추가.
관리 방법 - docker images: 이미지 목록 확인.- docker inspect: 이미지 메타데이터 확인.- docker history: 이미지 계층 확인.
장점 - 경량화, 이식성, 효율적인 업데이트.- 환경 독립적 애플리케이션 배포.

 

더보기

Docker 이미지 및 주요 명령어 표로 정리

 

명령어 설명  예제
docker pull Docker 이미지를 Docker Hub 또는 Private Registry에서 다운로드. docker pull nginx:latestdocker pull gcr.io/google-samples/hello-app:1.0
docker image inspect Docker 이미지의 메타데이터 및 내부 구조를 JSON 형식으로 확인. docker image inspect nginx:latestdocker image inspect --format="{{.Os}}" nginx:latest
docker image history 이미지 계층 정보를 확인하며, 각 명령(RUN, COPY 등)에 따른 이미지 생성 히스토리 제공. docker image history nginx:latest
docker login Docker Hub에 로그인하여 이미지 다운로드 및 업로드 가능. docker login
docker logout Docker Hub에서 로그아웃. docker logout

Docker 이미지의 주요 개념


항목  설명
이미지 계층 구조 Docker 이미지는 여러 계층으로 구성되며, 각 계층은 특정 명령(RUN, COPY 등)의 결과.
Immutable(불변성) 이미지는 한 번 생성되면 변경할 수 없음.새로운 요구사항은 새로운 이미지를 생성하여 처리.
Stateless 실행 중 상태 데이터는 컨테이너 외부(예: 볼륨)에 저장하여 애플리케이션 환경을 일관되게 유지.
레지스트리 Docker Hub 또는 Private Registry를 통해 이미지를 관리 및 공유.

Docker 명령어 사용 결과 예시

docker pull

docker pull nginx:latest
latest: Pulling from library/nginx
a378f10b3218: Pull complete
5b5e4b85559a: Pull complete
Digest: sha256:add4792d930c25dd2abf2ef9ea79de578097a1c175a16ab25814332fe33622de
Status: Downloaded newer image for nginx:latest

docker image inspect

docker image inspect nginx:latest
[
    {
        "Id": "sha256:593aee2afb642798b83a85306d2625fd7f089c0a1242c7e75a237846d80aa2a0",
        "RepoTags": ["nginx:latest"],
        "Created": "2023-10-25T01:21:47.343274012Z",
        "ContainerConfig": {
            "Hostname": "1e4063a23e5d",
            "ExposedPorts": {"80/tcp": {}}
        },
        ...
    }
]

docker image history

docker image history nginx:latest
IMAGE          CREATED       CREATED BY                                      SIZE
593aee2afb64   4 days ago    /bin/sh -c #(nop) CMD ["nginx" "-g" "daemon…   0B
<missing>      4 days ago    /bin/sh -c #(nop) EXPOSE 80                    0B
<missing>      2 weeks ago   /bin/sh -c #(nop) ADD file:55ad846fa191e6…     74.8MB

Docker Desktop

항목 설명
Docker Desktop Docker CLI와 GUI를 제공하여 Docker 컨테이너와 이미지를 관리하는 데 도움.
Docker Hub Public 및 Private Registry로 이미지를 저장 및 공유.
Access Token 관리 Docker Hub에서 Access Token을 생성하여 보안성을 강화하고, 관리 인터페이스에서 제어 가능.

Docker 명령어 활용 포인트

  • 이미지 확인:
    • 이미지 상태를 점검하고 필요한 경우 레지스트리에서 재다운로드.
  • 로그인 관리:
    • Docker Hub에 로그인하여 이미지를 푸시/풀하거나 Private Registry 관리.
  • 이미지 계층 분석:
    • docker image history와 docker image inspect를 통해 이미지 구성과 최적화 확인.

 

 

Docker Container와 Container 를 다루는 CLI

Docker Image와 Container 관계 요약

항목 설명
Docker Image 컨테이너를 실행하기 위한 운영체제(OS), 애플리케이션, 라이브러리 정보를 포함. 컨테이너의 "틀"과 같은 역할.
Docker Container Docker Image를 실행한 상태. 이미지로부터 생성된 실행 단위. 1개의 이미지로 다수의 컨테이너를 생성 가능 (1:N 관계).

 

비유:

  • Docker Image는 붕어빵 틀.
  • Docker Container는 틀에서 구워낸 붕어빵.

Docker Container와 관련 CLI 명령어 요약

1. Docker Image 관리

명령어 설명

명령어 설명
docker pull <이미지명:태그> 지정된 태그의 이미지를 다운로드.
docker images 다운로드된 이미지 목록 확인.
docker build -t <이미지명> Dockerfile을 기반으로 이미지를 빌드.
docker image prune 태그가 없는 불필요한(dangling) 이미지 삭제.

2. Docker Container 생성 및 실행

명령어 설명
docker create 컨테이너 생성만 수행, 실행은 하지 않음.
docker start <컨테이너명> 중지된 컨테이너 실행.
docker attach <컨테이너명> 실행 중인 컨테이너에 연결.
docker run create, start, attach를 한 번에 실행.
docker run -d 백그라운드에서 실행.
docker run -p <호스트포트>:<컨테이너포트> 호스트와 컨테이너의 포트 연결.
docker run -v <호스트경로>:<컨테이너경로> 호스트 디렉토리와 컨테이너 디렉토리를 연결.
docker run --rm 실행 후 종료 시 컨테이너를 자동 삭제.

3. 컨테이너 상태 관리

명령어 설명
docker ps 실행 중인 컨테이너 목록 확인.
docker ps -a 실행 중이거나 중지된 모든 컨테이너 확인.
docker stop <컨테이너명> 실행 중인 컨테이너 중지.
docker pause <컨테이너명> 컨테이너 일시 중지.
docker unpause <컨테이너명> 일시 중지된 컨테이너 재개.

4. 실행 중인 컨테이너 정보 확인

명령어  설명
docker top <컨테이너명> 컨테이너 내에서 실행 중인 프로세스 확인.
docker stats 컨테이너 리소스 사용량(CPU, 메모리 등) 확인.
docker logs <컨테이너명> 컨테이너 로그 확인.
docker inspect <컨테이너명> 컨테이너의 세부 정보 확인(JSON 형식).

5. Docker 리소스 정리

명령어 설명
docker container prune 중지된 모든 컨테이너 삭제.
docker image prune 사용되지 않는 태그 없는 이미지 삭제.
docker system prune 사용하지 않는 모든 리소스 삭제(이미지, 컨테이너, 네트워크, 볼륨 등).

추가 설명

  1. 컨테이너와 프로세스 관계
    Docker Container는 독립된 프로세스로 실행되며, ps -ef 명령으로 확인 가능.
  2. ps -ef | grep <컨테이너명>
  3. 컨테이너 로그 관리
    • Docker 로그는 Host OS에 저장되며, 용량 관리를 위해 주기적으로 정리 필요.
    • docker logs -f로 실시간 로그 확인 가능.
  4. 컨테이너 종료 코드
    • 정상 종료: 0
    • 명령 실행 실패: 126, 127
    • 강제 종료: 137, 143 등

도움이 될 추가 자료

 

'Docker > Docker' 카테고리의 다른 글

[Docker] Docker 모니터링&로깅  (0) 2025.02.04
[Docker] Docker Compose  (0) 2025.02.03
[Docker] Dockerfile  (1) 2025.02.01
[CI/CD] Github Actions CI  (0) 2025.01.31
[Docker] Docker+CI/CD  (0) 2025.01.30

QueryDSL

QueryDSL 소개

  • Entity의 매핑 정보를 활용하여 쿼리를 객체 또는 함수로 작성.
  • 주요 구성:
    • Q클래스: Entity의 쿼리 전용 클래스.
    • JPAQueryFactory: Q클래스를 사용하여 쿼리를 생성 및 실행.

QueryDSL 적용 방법

  1. JPAQueryFactory Bean 등록:
  2. @Configuration public class JPAConfiguration { @PersistenceContext private EntityManager entityManager; @Bean public JPAQueryFactory jpaQueryFactory() { return new JPAQueryFactory(entityManager); } }
  3. 쿼리 작성:
  4. @Autowired private JPAQueryFactory queryFactory; public List<User> selectUserByUsernameAndPassword(String username, String password) { QUser user = QUser.user; return queryFactory.selectFrom(user) .where(user.username.eq(username) .and(user.password.eq(password))) .fetch(); }

예제: 멘션된 쓰레드 조회

  • 조건: 내가 멘션된 쓰레드, 정렬 기준은 멘션된 시간 기준 내림차순.
  • 출력: 채널명, 작성자 정보, 본문, 이모지 정보, 댓글 정보 등.
public List<ThreadDetails> findMentionedThreads(Long userId) {
    QThread thread = QThread.thread;
    QMention mention = QMention.mention;

    return queryFactory
        .select(
            Projections.bean(ThreadDetails.class,
                thread.channel.name.as("channelName"),
                thread.user.username.as("authorName"),
                thread.user.profileImageUrl.as("authorProfileImage"),
                thread.message.as("message"),
                thread.emotions.any().body.as("emotions"),
                thread.comments.any().message.as("commentMessages")
            ))
        .from(thread)
        .join(thread.mentions, mention)
        .where(mention.user.id.eq(userId))
        .orderBy(mention.createdAt.desc())
        .fetch();
}

 

 

Auditing

Auditing 소개

  • 엔티티 생성 및 수정 시 자동으로 작성자와 시간을 기록.

적용 방법

  1. @EnableJpaAuditing 추가:
  2. @EnableJpaAuditing(auditorAwareRef = "userAuditorAware") @SpringBootApplication public class Application {}
  3. 공통 Base 클래스 작성:
  4. @MappedSuperclass @EntityListeners(AuditingEntityListener.class) public class BaseTimeEntity { @CreatedDate private LocalDateTime createdAt; @LastModifiedDate private LocalDateTime modifiedAt; @CreatedBy @ManyToOne private User createdBy; @LastModifiedBy @ManyToOne private User modifiedBy; }
  5. AuditorAware 구현:
  6. @Service public class UserAuditorAware implements AuditorAware<User> { @Override public Optional<User> getCurrentAuditor() { Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); if (authentication == null || !authentication.isAuthenticated()) return Optional.empty(); return Optional.of(((UserDetailsImpl) authentication.getPrincipal()).getUser()); } }

 

Dynamic Insert/Update

Dynamic Insert

  • @DynamicInsert:
    • Insert 쿼리에서 null 값을 제외한 필드만 포함.
@DynamicInsert
public class User {
    private String username;
    private String password;
}

적용 전:

insert into users (username, password, id) values (?, ?, ?)

적용 후:

insert into users (username, id) values (?, ?)

Dynamic Update

  • @DynamicUpdate:
    • Update 쿼리에서 변경된 값만 포함.
@DynamicUpdate
public class User {
    private String username;
    private String password;
}

적용 전:

update users set username=?, password=? where id=?

적용 후:

update users set username=? where id=?

요약

기능  설명  적용 예시
QueryDSL - 객체 기반으로 쿼리를 작성하여 가독성과 유지보수성 향상.- JPAQueryFactory와 Q클래스 활용. - 사용자 검색: selectFrom(user).where(user.username.eq("John")).fetch();
Auditing - 엔티티 생성/수정 시 작성자와 시간을 자동 기록. - @CreatedBy, @LastModifiedBy를 통해 작성자 자동 기록.
Dynamic 설정 - Insert/Update 시 null 값을 제외한 필드만 처리.- 성능 최적화. - @DynamicInsert, @DynamicUpdate

 

'DB > JPA ( Java Persistence API )' 카테고리의 다른 글

[JPA] Lock (동시성)  (1) 2025.02.24
[JPA] N + 1 문제란 무엇인가  (0) 2025.02.14
[JPA] 테이블 객체  (0) 2025.01.27
[JPA] 쿼리 파일 만들기 (QueryMapper)  (0) 2025.01.26
[JPA] 데이터베이스 연결 (Driver)  (1) 2025.01.25

테이블 객체 다루는법

 

[1] Cascade (영속성 전이)

항목  설명  예시 코드
사용 위치 - 연관관계 주인의 반대편에 설정.- 주로 부모 엔티티(@OneToMany, @OneToOne)에 설정. java<br>@OneToMany(cascade = CascadeType.ALL)<br>private List<File> files;<br>
사용 조건 - 연관된 엔티티의 라이프사이클이 동일하거나 유사할 때 사용.- 현재 엔티티에서만 전이되도록 설정. 예: 게시글과 첨부파일, 게시글 삭제 시 첨부파일도 삭제됨.
옵션 종류 - ALL: 모든 상태 전이를 포함.- PERSIST: 저장 전이.- REMOVE: 삭제 전이.- MERGE: 병합 전이.- REFRESH: 갱신 전이.- DETACH: 비영속 전이. java<br>@OneToOne(cascade = {CascadeType.PERSIST, CascadeType.REMOVE})<br>private Profile profile;<br>
주요 고려 사항 - 다른 엔티티에서 동일한 대상에 대해 영속성 전이 설정 금지.- 불필요한 전이 설정은 데이터 불일치 및 성능 저하를 초래할 수 있음.  

Cascade 옵션 상세 설명

옵션 설명
ALL - 모든 상태 전이를 포함.동일한 라이프사이클을 가진 엔티티에 대해 사용.
PERSIST - 부모 엔티티를 저장하면, 연관된 엔티티도 함께 저장.
REMOVE - 부모 엔티티를 삭제하면, 연관된 엔티티도 함께 삭제.
MERGE - 부모 엔티티가 병합될 때, 연관된 엔티티도 병합.
REFRESH - 부모 엔티티를 새로고침(갱신)하면, 연관된 엔티티도 새로고침.
DETACH - 부모 엔티티가 비영속 상태로 전환되면, 연관된 엔티티도 비영속 상태로 전환.

예제: 게시글과 첨부파일 관계

@Entity
public class Post {

    @Id
    @GeneratedValue
    private Long id;

    private String title;

    @OneToMany(mappedBy = "post", cascade = CascadeType.ALL, orphanRemoval = true)
    private List<File> files = new ArrayList<>();

    public void addFile(File file) {
        files.add(file);
        file.setPost(this);
    }

    public void removeFile(File file) {
        files.remove(file);
        file.setPost(null);
    }
}

@Entity
public class File {

    @Id
    @GeneratedValue
    private Long id;

    private String fileName;

    @ManyToOne
    @JoinColumn(name = "post_id")
    private Post post;
}

주요 사용 시나리오

  1. 게시글 삭제 시 첨부파일도 삭제:
    • CascadeType.REMOVE를 사용해 부모 엔티티(Post) 삭제 시 자식 엔티티(File)도 삭제.
  2. 게시글 저장 시 첨부파일도 저장:
    • CascadeType.PERSIST를 사용해 Post 저장 시 File도 저장.
  3. 연관된 엔티티가 독립적으로 관리되지 않도록 제한:
    • 동일 라이프사이클 보장.

주의사항

  1. Cascade의 과도한 사용 금지:
    • 모든 연관관계에 설정 시 데이터 무결성 문제 발생 가능.
  2. ALL 사용 신중:
    • 모든 상태 전이를 강제하므로, 필요하지 않은 전이가 포함될 수 있음.
  3. 단방향 설정 추천:
    • 불필요한 양방향 전이는 복잡도를 높이고 성능을 저하시킬 수 있음.

 

[2] orphanRemoval (고아 객체 제거) 

항목  설명  예시 코드
사용 위치 - @OneToMany 또는 @OneToOne 관계에서 부모 엔티티에 설정. java<br>@OneToMany(mappedBy = "parent", orphanRemoval = true)<br>private List<Child> childList;<br>
사용법 - 부모 엔티티에서 자식 엔티티를 제거할 때, 고아 객체(매핑 정보가 없는 자식)를 자동으로 삭제. java<br>Parent parent = em.find(Parent.class, id);<br>parent.getChildList().remove(0); // 자식 엔티티 삭제<br>
Cascade.REMOVE와 차이 - Cascade.REMOVE: 부모 엔티티를 삭제하면 연관된 자식 엔티티도 삭제.- orphanRemoval: 부모의 리스트에서 자식 엔티티를 제거하면 자식 엔티티도 삭제. - 두 옵션을 함께 설정하면 자식 엔티티의 생명주기가 부모와 완전히 동일.
옵션 - true: 고아 객체 제거 활성화.- false: 고아 객체 제거 비활성화. java<br>@OneToMany(mappedBy = "parent", cascade = CascadeType.ALL, orphanRemoval = true)<br>private List<Child> children;<br>
추천 설정 - orphanRemoval = true + Cascade.ALL 조합 사용.- 자식 엔티티의 생명주기를 부모와 동일하게 관리.- 자식의 독립적인 Repository 없이 관리 가능.  

주요 사용 시나리오

  1. 부모-자식 관계에서 고아 객체 처리:
    • 부모 엔티티에서 자식 엔티티를 리스트에서 제거하면, 매핑 정보가 없는 자식(고아 객체)을 자동으로 삭제.
    • 예: 게시글에서 첨부파일 제거 시, DB에서도 해당 첨부파일 삭제.
  2. 자식의 라이프사이클 부모에 종속:
    • Cascade.ALL과 함께 사용하여 자식 엔티티가 부모의 라이프사이클에 완전히 종속되도록 설정.
    • 자식 엔티티의 생명주기를 부모 엔티티에서만 관리 가능.

예제 코드

1. 고아 객체 제거 설정

@Entity
public class Parent {

    @Id
    @GeneratedValue
    private Long id;

    @OneToMany(mappedBy = "parent", cascade = CascadeType.ALL, orphanRemoval = true)
    private List<Child> childList = new ArrayList<>();

    public void addChild(Child child) {
        childList.add(child);
        child.setParent(this);
    }

    public void removeChild(Child child) {
        childList.remove(child);
        child.setParent(null);
    }
}

@Entity
public class Child {

    @Id
    @GeneratedValue
    private Long id;

    @ManyToOne
    @JoinColumn(name = "parent_id")
    private Parent parent;
}

2. 사용 예제

Parent parent = em.find(Parent.class, parentId);
Child child = parent.getChildList().get(0);

// 자식 엔티티를 리스트에서 제거하면 자동으로 삭제됨
parent.removeChild(child);
em.flush(); // delete 쿼리 실행

장점 및 주의사항

장점 주의사항
- 자식 엔티티의 생명주기를 부모와 동일하게 관리 가능.- 자식 엔티티의 독립적인 Repository가 불필요.- 매핑 테이블에서 많이 사용. - 연관 관계의 복잡성 증가 가능.- 자식 엔티티가 다른 엔티티에서도 참조된다면, orphanRemoval 설정은 사용하면 안 됨.- 부모-자식 관계가 명확할 때만 사용 권장.

 

 

[3] Fetch (조회 시점) 

항목  설명 예시 코드
사용 위치 - 연관관계를 맺는 엔티티에서 @ElementCollection, @ManyToMany, @OneToMany, @ManyToOne, **@OneToOne**에 설정 가능. java<br>@OneToMany(fetch = FetchType.LAZY)<br>private List<Comment> comments;<br>
사용법 - 기본적으로 LAZY 설정 후 필요 시 fetch join으로 조회.- 항상 함께 조회되는 관계는 EAGER 설정. java<br>@OneToOne(fetch = FetchType.EAGER)<br>private Profile profile;<br>
옵션 (FetchType) - EAGER: 부모 조회 시 연관된 자식도 즉시 조회.- LAZY: 연관된 자식은 실제로 필요할 때 조회. java<br>@ManyToOne(fetch = FetchType.LAZY)<br>@JoinColumn(name = "parent_id")<br>private Parent parent;<br>
Query 활용 - fetch join: 기본 설정이 LAZY일 때도 즉시 로딩 가능. java<br>SELECT p FROM Post p JOIN FETCH p.comments WHERE p.id = :id;<br>

FetchType 옵션 비교

옵션  설명  장점 단점
EAGER - 즉시 로딩.- 부모 엔티티 조회 시 자식 엔티티도 함께 조회. - 편리함: 한 번의 조회로 연관 데이터 로드.- 항상 필요한 경우 적합. - 불필요한 데이터 로드로 성능 저하.- N+1 문제 유발 가능.
LAZY - 지연 로딩.- 부모 엔티티 조회 시 자식은 실제로 필요할 때 조회. - 성능 최적화: 실제 필요한 경우에만 데이터 조회.- 불필요한 데이터 로드 방지. - 필요 시 추가 쿼리 발생.- fetch join 필요 시 복잡성 증가.

추천 설정 및 사용 예제

기본 설정

  • 대부분의 연관관계는 **LAZY**로 설정:
    • 불필요한 데이터 로드를 방지.
    • 필요 시 명시적으로 fetch join을 통해 데이터 조회.

항상 함께 쓰이는 관계

  • EAGER 설정:
    • 예: @OneToOne에서 프로필과 사용자 관계처럼 항상 함께 조회되어야 하는 경우.

실제 사용 예제

1. FetchType 설정 예제

@Entity
public class User {

    @Id
    @GeneratedValue
    private Long id;

    @OneToOne(fetch = FetchType.EAGER)
    private Profile profile; // 즉시 로딩

    @OneToMany(mappedBy = "user", fetch = FetchType.LAZY)
    private List<Post> posts; // 지연 로딩
}

2. Fetch Join을 활용한 즉시 로딩

// 기본적으로 FetchType.LAZY 설정
@Entity
public class Post {

    @Id
    @GeneratedValue
    private Long id;

    @OneToMany(mappedBy = "post", fetch = FetchType.LAZY)
    private List<Comment> comments;
}

// Fetch Join으로 LAZY 관계 즉시 로딩
String query = "SELECT p FROM Post p JOIN FETCH p.comments WHERE p.id = :id";
TypedQuery<Post> typedQuery = em.createQuery(query, Post.class);
typedQuery.setParameter("id", postId);
Post post = typedQuery.getSingleResult();

주의사항

  1. N+1 문제:
    • EAGER 설정 시, 연관된 자식 엔티티를 매번 추가로 조회해 성능 문제가 발생할 수 있음.
    • 해결책: fetch join 활용.
  2. 불필요한 로딩 방지:
    • 필요하지 않은 데이터를 EAGER로 설정하지 않도록 주의.
  3. 실무 권장 사항:
    • 대부분 LAZY 설정 후, 필요 시 명시적으로 fetch join 사용.
    • **EAGER**는 정말 항상 함께 조회되는 관계에만 설정.

 

 

테이블 객체로 자동 쿼리 생성하기

SprintData Common 의 CRUDRepository + PagingAndSortingRepository 이 쿼리기능을 제공

 

[1] JPA Repository 쿼리 기능 

항목  설명 예시 코드
기본 정의 - Repository: Marker Interface, 자체 기능 없음.- JpaRepository: CRUD, 페이징, 정렬 기능 제공. java<br>public interface UserRepository extends JpaRepository<User, Long> {}<br>
등록 방식 - JpaRepository는 **@EnableJpaRepositories**로 자동 등록.- 구현체로 **SimpleJpaRepository**가 사용. java<br>@SpringBootApplication<br>@EnableJpaRepositories<br>public class Application {}<br>
기능 차이 (기존 vs 새로운) - 기존 Repository:Raw JPA 기반의 기본 CRUD 기능 제공.- JpaRepository:CRUD, 페이징, 정렬 등 제공. java<br>@Repository<br>public class UserRepository { ... }<br>// JpaRepository로 변경<br>public interface UserRepository extends JpaRepository<User, Long> {}<br>

주요 내용

기존 Repository

  • 설정: @Repository 애노테이션을 붙여 사용.
  • 기능:
    • Raw JPA 기반의 CRUD 구현.
    • 직접 EntityManager 사용 필요.
    • DB별 예외 처리를 수동으로 구현.

JpaRepository

  • 설정: JpaRepository<Entity, ID>를 상속.
  • 기능:
    • CRUD, 페이징, 정렬 기능 내장.
    • Spring Data JPA에 의해 구현체(SimpleJpaRepository)가 자동으로 생성 및 등록.
    • 더 적은 코드로 복잡한 기능 구현 가능.

코드 비교: 기존 Repository vs JpaRepository

기존 Repository

@Repository
public class UserRepository {

    @PersistenceContext
    private EntityManager entityManager;

    public User insertUser(User user) {
        entityManager.persist(user);
        return user;
    }

    public User selectUser(Long id) {
        return entityManager.find(User.class, id);
    }
}

JpaRepository로 변경

public interface UserRepository extends JpaRepository<User, Long> {
}

JpaRepository의 주요 제공 기능

  1. CRUD 기능:
    • save(): 엔티티 저장/수정.
    • findById(): 기본 키로 엔티티 조회.
    • delete(): 엔티티 삭제.
  2. 페이징 및 정렬:
    • findAll(Pageable pageable): 페이징 조회.
    • findAll(Sort sort): 정렬된 목록 조회.
  3. 커스텀 쿼리 작성:
    • 메서드 이름 기반 쿼리 생성 (findByName).
    • JPQL 또는 네이티브 쿼리 작성 가능 (@Query).

Spring Data JPA의 장점

  1. 자동 빈 등록:
    • @EnableJpaRepositories를 통해 자동으로 Repository 구현체 등록.
  2. 간결한 코드:
    • 구현체 없이 인터페이스만으로 복잡한 기능 제공.
  3. 일관된 예외 처리:
    • 데이터 접근 계층의 일관된 예외 체계.

결론

  • 기존 @Repository 방식은 코드가 길고 직접 EntityManager를 사용해야 하지만,
  • JpaRepository를 사용하면 CRUD, 페이징, 정렬 등 다양한 기능을 더 간단하게 구현 가능.

 

 

[2] JpaRepository 쿼리 사용 방법 

항목  설명  예시 코드
접두어 - 쿼리 동작을 지정.- Find, Get, Query, Count 등 사용 가능. java<br>List<User> findByName(String name);<br>long countByName(String name);<br>
도입부 - 중복 제거(Distinct), 첫 N개만 조회(First(N), Top(N)) 등. java<br>List<User> findDistinctByName(String name);<br>List<User> findTop3ByName(String name);<br>
프로퍼티 표현식 - 속성 경로를 언더스코어로 연결하여 작성.- 예: Person.Address.ZipCode → findByAddress_ZipCode java<br>List<User> findByAddress_ZipCode(String zipCode);<br>
조건식 - 연산 조건 설정 (IgnoreCase, Between, LessThan, GreaterThan, Like, Contains). java<br>List<User> findByNameIgnoreCase(String name);<br>List<User> findByAgeBetween(int minAge, int maxAge);<br>
정렬 조건 - `OrderBy{프로퍼티}Asc Desc`.
리턴 타입 - E, Optional<E>, List<E>, Page<E>, Slice<E>, Stream<E>. java<br>Page<User> findByName(String name, Pageable pageable);<br>Slice<User> findByName(String name, Pageable pageable);<br>
매개변수 - 페이징: Pageable 사용.- 정렬: Sort 사용. java<br>List<User> findByName(String name, Pageable pageable);<br>List<User> findByName(String name, Sort sort);<br>

실습 예제 및 설명

기본 쿼리

List<User> findByNameAndPassword(String name, String password); // 조건식
List<User> findByNameIgnoreCase(String name);                  // 대소문자 무시
List<Person> findByNameOrderByAgeDesc(String name);            // 정렬

페이징 처리

Pageable firstPage = PageRequest.of(0, 3);  // 첫 페이지, 페이지 크기 3
Pageable sortedByName = PageRequest.of(1, 5, Sort.by("name")); // 두 번째 페이지, 정렬 추가

Page<User> pageResult = userRepository.findByName("John", firstPage);
  • Page: 페이징 정보와 전체 데이터 수를 포함.
  • Slice: 다음 페이지 여부만 확인 가능.

정렬 처리

// 정렬만 수행
List<Product> productsSortedByName = productRepository.findAll(Sort.by("name").ascending());

// 페이징과 정렬 함께
Pageable sortedByPriceAndName = PageRequest.of(0, 5, Sort.by("price").descending().and(Sort.by("name")));
Page<Product> pageResult = productRepository.findAll(sortedByPriceAndName);

스트림 사용

try (Stream<User> userStream = userRepository.readAllByNameNotNull()) {
    userStream.forEach(user -> System.out.println(user.getName()));
}
  • 스트림 사용 후 자원 해제를 위해 try-with-resources 권장.

주요 특징 및 추천 활용

  1. 기본 설정:
    • 메서드 이름만으로도 대부분의 쿼리 구현 가능.
    • 명확하고 간결한 코드 작성 가능.
  2. 페이징과 정렬:
    • 페이징 시 PageSlice 선택적으로 사용.
    • 복합 정렬 시 **Sort**를 활용.
  3. 스트림:
    • 대량 데이터 처리 시 유용.

 

[3] JpaRepository 효율적으로 사용하는 방법 

항목  설명 예시 코드
1. Optional 제거하기 - findById()의 반환값인 Optional을 직접 처리하지 않도록 기본 메서드를 정의하여 비즈니스 로직에서 간결하게 처리. java<br>default User findUserById(Long id) {<br> return findById(id).orElseThrow(() -><br> new DataNotFoundException("User not found"));<br>}<br>
2. 메서드명 간소화하기 - 복잡한 쿼리 메서드명을 기본 메서드로 감싸 간결하고 명확한 이름으로 제공. java<br>default List<Product> findProductsByCategoryAndPriceRange(String category, BigDecimal min, BigDecimal max) {<br> return findAllByCategoryAndPriceGreaterThanEqualAndPriceLessThanEqualOrderByPriceAsc(category, min, max);<br>}<br>
3. 비즈니스 로직 통합 - Repository의 기본 메서드들을 조합하여 고차 작업을 처리하는 메서드 제공.- 데이터베이스와의 상호작용을 간소화. java<br>default void updateUserContact(Long userId, String newContact) {<br> findById(userId).ifPresent(user -> {<br> user.setContact(newContact);<br> save(user);<br> });<br>}<br>

상세 설명 및 추천 활용

1. Optional 제거하기

  • 문제: Optional 처리로 인해 코드가 복잡해질 수 있음.
  • 해결: 기본 메서드를 활용하여 orElseThrow()로 예외를 처리.
  • 추천 시나리오:
    • 엔티티가 반드시 존재해야 하는 경우.

2. 메서드명 간소화하기

  • 문제: 긴 메서드명으로 인해 가독성이 떨어질 수 있음.
  • 해결: 복잡한 메서드를 기본 메서드로 감싸서 간결한 이름 제공.
  • 추천 시나리오:
    • 복잡한 조건이 포함된 쿼리 메서드.

3. 비즈니스 로직 통합

  • 문제: 데이터베이스 작업과 비즈니스 로직이 분리되지 않으면 중복 코드 발생.
  • 해결: 기본 메서드로 데이터 처리 및 로직 결합.
  • 주의사항:
    • Repository는 데이터 접근 계층에 집중하고, 비즈니스 로직은 서비스 계층에서 처리하는 것이 일반적.
    • 간단한 작업에 한해 Repository에서 처리.

예제 코드

1. Optional 제거

public interface UserRepository extends JpaRepository<User, Long> {

    default User findUserById(Long id) {
        return findById(id).orElseThrow(() -> 
            new DataNotFoundException("User not found with id: " + id));
    }
}

2. 메서드명 간소화

public interface ProductRepository extends JpaRepository<Product, Long> {

    // 긴 메서드 이름
    List<Product> findAllByCategoryAndPriceGreaterThanEqualAndPriceLessThanEqualOrderByPriceAsc(String category, BigDecimal minPrice, BigDecimal maxPrice);

    // 간단한 메서드 이름
    default List<Product> findProductsByCategoryAndPriceRange(String category, BigDecimal minPrice, BigDecimal maxPrice) {
        return findAllByCategoryAndPriceGreaterThanEqualAndPriceLessThanEqualOrderByPriceAsc(category, minPrice, maxPrice);
    }
}

3. 비즈니스 로직 통합

public interface UserRepository extends JpaRepository<User, Long> {

    default void updateUserContact(Long userId, String newContact) {
        findById(userId).ifPresent(user -> {
            user.setContact(newContact);
            save(user);
        });
    }
}

추천 사용 전략

  1. Optional 제거:
    • findById() 반환값을 비즈니스 로직에서 간결하게 처리.
  2. 메서드명 간소화:
    • 복잡한 조건이 포함된 메서드를 간단하고 읽기 쉽게 변환.
  3. 비즈니스 로직 통합:
    • 간단한 작업에 한해 Repository에서 직접 처리. 복잡한 로직은 서비스 계층에 분리.

 

테이블 객체로 페이지 조회하기

 

[1] JpaRepository 페이징 및 정렬 

페이징 처리 프로세스

  1. PageRequest 생성:
    • PageRequest.of(page, size)로 페이지 번호와 크기를 설정.
    • 정렬이 필요한 경우 추가적으로 Sort를 전달.
  2. 메서드 호출:
    • Pageable 객체를 JpaRepository 메서드에 전달.
    • 반환값은 Page<T>, Slice<T>, 또는 List<T>로 설정 가능.
  3. 응답 처리:
    • Page<T> 또는 Slice<T> 객체에서 메타정보와 데이터를 추출하여 비즈니스 로직 처리.

주요 클래스 및 메서드

Pageable 생성

  • 기본 생성:
    Pageable pageable = PageRequest.of(0, 10); // 페이지 번호: 0, 페이지 크기: 10
    
  • 정렬 추가:
    Pageable pageable = PageRequest.of(0, 10, Sort.by("name").ascending());
    

Pageable 주요 메서드

메서드 설명

getTotalPages() 전체 페이지 수 반환.
getTotalElements() 전체 요소 수 반환.
getNumber() 현재 페이지 번호 반환.
getSize() 페이지 크기 반환.
getContent() 현재 페이지의 데이터(List<T>) 반환.
hasNext() 다음 페이지 존재 여부 반환.
isFirst() 현재 페이지가 첫 페이지인지 반환.

Page 응답 예제

{
  "content": [
    { "id": 1, "username": "User1", "address": "Korea", "age": 25 },
    { "id": 2, "username": "User2", "address": "USA", "age": 30 }
  ],
  "pageable": {
    "pageNumber": 0,
    "pageSize": 2,
    "sort": { "sorted": false, "unsorted": true }
  },
  "totalPages": 10,
  "totalElements": 20,
  "first": true,
  "last": false
}

페이징 반환 타입 비교

반환 타입 설명 장점 단점

Page - 전체 페이지 및 요소 수 포함.- 게시판 형태. - 전체 정보 확인 가능.- 페이징 UI에 적합. - 추가적인 카운트 쿼리 발생.
Slice - 다음 페이지 여부만 확인 가능.- "더보기" 형태. - 카운트 쿼리 없음.- 성능 최적화. - 전체 정보 제공 불가.
List - 단순 목록 반환.- 정렬 가능. - 쿼리 단순화.- 카운트 쿼리 없음. - 페이지 메타정보 제공 불가.

정렬 처리

컬럼 값 기준 정렬

Sort sort = Sort.by("name").ascending();
Pageable pageable = PageRequest.of(0, 10, sort);
Page<User> page = userRepository.findAll(pageable);

다중 정렬

Sort sort = Sort.by("name").ascending().and(Sort.by("age").descending());
Pageable pageable = PageRequest.of(0, 10, sort);
Page<User> page = userRepository.findAll(pageable);

Alias를 기준으로 정렬

@Query("SELECT u.user_name AS userName FROM User u WHERE u.address = :address")
List<User> findByAddress(@Param("address") String address, Sort sort);

// 호출 시
List<User> users = userRepository.findByAddress("Korea", Sort.by("userName").ascending());

SQL 함수 기반 정렬

List<User> users = userRepository.findByUsername(
    "user", JpaSort.unsafe("LENGTH(password)").descending());

실습 코드

페이징 처리

Pageable pageable = PageRequest.of(1, 5, Sort.by("name").descending());
Page<User> page = userRepository.findByAddress("Korea", pageable);

List<User> users = page.getContent();
long totalElements = page.getTotalElements();
int totalPages = page.getTotalPages();

Slice 처리

Pageable pageable = PageRequest.of(1, 5, Sort.by("name").ascending());
Slice<User> slice = userRepository.findByAddress("Korea", pageable);

List<User> users = slice.getContent();
boolean hasNext = slice.hasNext();

추천 사용 전략

  1. Page와 Slice:
    • 게시판: Page<T>를 사용하여 전체 정보 제공.
    • "더보기" 기능: Slice<T>로 성능 최적화.
  2. 정렬:
    • 간단한 정렬: Sort 사용.
    • 복잡한 정렬: SQL 함수와 Alias 활용.
  3. 최적화:
    • 카운트 쿼리 비용이 큰 경우 Slice 또는 List로 대체.

 

 

Level 1: 기본 기능 구현 및 코드 개선

1. 코드 개선 퀴즈 - @Transactional의 이해

  • 할 일을 저장하는 API(/todos) 호출 시 Connection is read-only 에러가 발생.
  • 정상적으로 할 일을 저장할 수 있도록 @Transactional 설정을 수정.

2. 코드 추가 퀴즈 - JWT의 이해

  • 요구사항:
    • User 테이블에 nickname 컬럼 추가 (중복 가능).
    • JWT에서 nickname을 꺼내 프론트엔드에 전달.

3. 코드 개선 퀴즈 - AOP의 이해

  • changeUserRole() 메서드 실행 전에 로그를 남기는 AOP 구현.
  • AOP 클래스 AdminAccessLoggingAspect 수정 필요.

4. 테스트 코드 퀴즈 - 컨트롤러 테스트의 이해

  • todo_단건_조회_시_todo가_존재하지_않아_예외가_발생한다() 테스트 실패.
  • 테스트가 정상적으로 통과하도록 수정.

5. 코드 개선 퀴즈 - JPA의 이해

  • 할 일 검색 기능 확장:
    • weather 조건으로 검색 (조건은 선택적).
    • 수정일 기준으로 기간 검색 (기간 조건도 선택적).
  • JPQL을 활용해 조건 처리.

Level 2: 고급 JPA 기능 구현

6. JPA Cascade

  • 할 일을 생성한 사용자가 자동으로 담당자로 등록되도록 cascade 설정.

7. N+1 문제 해결

  • CommentController의 getComments() API에서 N+1 문제 발생.
  • JPA fetch join을 사용하여 문제 해결.

8. QueryDSL

  • JPQL로 작성된 findByIdWithUser 메서드를 QueryDSL로 변경.
  • N+1 문제 없이 데이터 조회 구현.

9. Spring Security

  • 기존 Filter와 Argument Resolver 코드를 Spring Security로 변경.
  • 기존 권한 및 접근 제어 로직 유지.
  • JWT 기반 인증 방식 유지.

Level 3: 도전 과제

10. QueryDSL을 사용한 검색 기능 구현

  • 검색 조건:
    • 제목 키워드 검색 (부분 일치).
    • 생성일 범위 검색 (최신순 정렬).
    • 담당자 닉네임 검색 (부분 일치).
  • 검색 결과:
    • 일정의 제목만 반환.
    • 일정의 담당자 수와 댓글 개수 포함.
  • 기능 요구사항:
    • Projections를 사용해 필요한 데이터만 반환.
    • 페이징 처리된 결과 반환.

 

 

[회고]

 

이번 코드는 기능 개선과 오류의 확인, 간단한 구현이 전부였다. 오히려 내용적인 부분보다는 이론적인 부분을 저오학히 알고 있는지를 확인하는 느낌이 강했던 것 같다. 다만 이번 과제를 하면서 느낀점이, 제대로 하고 있는가?라는 질문이 나왔던 것 같다.

 

현재까지는 이론을 듣고 그저 필요한 기능에 맞춰 구현했지만, 개발자의 필요한 능력은 팀플을 하면서 느낀바로는 문제 해결능력이었다. 더 효율적인 코드를 위해 앞으로의 유연한 확장을 위해 개발을 하는 것이 가장 큰 목표라고 느꼈으며, 코드를 짜는 것 자체는 상당히 중요한 건 맞지만 조금 보조적인 느낌이라고 느꼈다.

 

이렇게 생각하고 나니, 지금 제대로 학습을 하고 있는가?라는 생각이 들 수 밖에 없었다.
1. 왜 이걸 썼는가?

= 레디스는 빠르니까 데이터를 매핑해서 사용하거나 요청하는데 있어 조금이라도 더 속도가 빨라질 것 같아서 사용했다.
2. 레디스는 안정성이 떨어지는데 그 점은 괜찮은가?

= 안정성이 떨어지는 부분을 인지하고 있고 일시적으로만 저장될 데이터만 저장에 이용하였고 처리가 완전히 끝난 완전한 데이터만 Mysql로 저장했다.

 

지금까지는 이렇게 생각했다. 하지만 이건 내가 그나마 많이 사용한 기능이기에 부족하지만 이정도라도 답변이 가능했지만, 사실 생각지 못했던 marven gradle 중 왜 gradle을 사용했는가와 같은 답변에는 대답하기 힘들다는 생각이 들었다. 무엇보다 시간이 많이 없는 상태에서 어떻게 공부하는게 효과적인가 라는 질문이 계속 들었다.

 

이렇게 보니 앞으로의 최종 프로젝트에서 원래는 쿠버네티스, 엘라스틱서치와 같은 기능을 사용하려했지만, 과연 내가 이 기능의 이론이 아니라 정확히 이해하고 언제 사용해야하는지 그리고 각 단점을 어떻게 보완할지와 같은 질문에 대답할 수 있는가? 라는 질문도 생겼다.

 

"이론을 이해하고 적제 적소에 사용할 수 있는 능력, 그리고 각 기능의 단점을 보완하고 장점을 살려 문제를 해결하는 것"이게 현재까지 느끼는 개발자의 능력이었지만, 그저 코드만 짤 뿐이라면 위의 2개의 질문에 답할 수 없다.

 

과연 많은 기능을 포함한 프로젝트를 지금의 이해도로 만들어도 될까?

 

이론을 공부만 해서는 특정 상황을 질문을 하고 해결하라고 하면 답하기 힘들지 않을까?

 

그렇다면 어떻게 공부해야하는가, 아는 친구는 ORM의 작동 방식에 대해서도 상세히 알아야한다고 했다. 사실 자동으로 처리하니 그전까지는 ORM이 어노테이션을 이용해 자동으로 처리하는 것에 대해 아무생각이 없었다. 솔직히 여기까지 공부해야한다고? 생각이 들었다. 어떻게, 어디까지 공부해야하는걸까?

 

이 과제를 진행하면서 3가지가 가장 큰 고민이라는 생각이 든다.

 

'Project > Spring' 카테고리의 다른 글

[Spring] IOC & DI  (0) 2025.01.23
스프링 NEWSFEED 협업 프로젝트  (1) 2024.12.27
일정표를 만들어 보자! 업데이트!  (2) 2024.12.19
일정표를 만들어 보자!  (2) 2024.12.09
[ Spring ] 쇼핑몰 프로젝트 회고  (0) 2024.11.25

MyBatis

   
정의 SQL Mapper의 한 종류로, JDBC 프로그래밍을 단순화하고 SQL과 코드를 분리.
주요 목적 - 반복되는 JDBC 코드 간소화- SQL과 애플리케이션 코드를 분리 관리.
특징 - SQL 쿼리 중심의 데이터 처리.- XML 파일과 어노테이션으로 SQL 관리.
장점 - SQL 작성에 유연성.- 빠른 개발 가능.- 코드와 SQL 분리로 유지보수 용이.
한계점 - SQL을 직접 작성해야 하므로 피로도 증가.- CRUD 코드 반복 발생.- DB 및 테이블에 종속적.
적합한 경우 - 데이터베이스 중심의 애플리케이션.- SQL에 세부적인 제어가 필요한 프로젝트.
부적합한 경우 - 객체 중심 설계(OOP)가 중요한 프로젝트.- 테이블 변경이 잦은 프로젝트.

 

 

MyBatis 의 동작

더보기

(1) ~ (3)은 응용 프로그램 시작시 수행되는 프로세스입니다.

(1) 응용 프로그램이 SqlSessionFactoryBuilder를 위해 SqlSessionFactory를 빌드하도록 요청합니다.

 

(2) SqlSessionFactoryBuilder는 SqlSessionFactory를 생성하기 위한 Mybatis 구성 파일을 읽습니다.

 

(3) SqlSessionFactoryBuilder는 Mybatis 구성 파일의 정의에 따라 SqlSessionFactory를 생성합니다.

 

 

(4) ~ (10)은 클라이언트의 각 요청에 대해 수행되는 프로세스입니다.

(4) 클라이언트가 응용 프로그램에 대한 프로세스를 요청합니다.

 

(5) 응용 프로그램은 SqlSessionFactoryBuilder를 사용하여 빌드된 SqlSessionFactory에서 SqlSession을 가져옵니다.

 

(6) SqlSessionFactory는 SqlSession을 생성하고 이를 애플리케이션에 반환합니다.

 

(7) 응용 프로그램이 SqlSession에서 매퍼 인터페이스의 구현 개체를 가져옵니다.

 

(8) 응용 프로그램이 매퍼 인터페이스 메서드를 호출합니다.

 

(9) 매퍼 인터페이스의 구현 개체가 SqlSession 메서드를 호출하고 SQL 실행을 요청합니다.

 

(10) SqlSession은 매핑 파일에서 실행할 SQL을 가져와 SQL을 실행합니다.

 

  • SqlSession Factory Builder (1), (2), (3)
    • MyBatis 설정 파일을 읽어와서
    • 설정정보 기반으로 SqlSession Factory 를 생성하는 빌더 객체
  • MyBatis Config File (2)
    • 매핑해줄 객체가 들어있는 패키지 경로와
    • Mapping File 목록을 지정해주는 설정 파일
<!-- /resources/mybatis-config.xml -->
<!DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
    <typeAliases>
        <package name="com.thesun4sky.querymapper.domain"/>
    </typeAliases>
    <mappers>
        <mapper resource="mapper/UserMapper.xml"/>
    </mappers>
</configuration>

 

  • SqlSession Factory (3), (5), (6)
    • 설정에 맞게 SqlSession 을 생성하여 들고있는 객체
  • SqlSession (6), (7), (9), (10)
    • Mapping File 에서 쿼리를 조회해서 쿼리를 수행하고 응답을 받아올 수 있는 세션 객체
  • Mapper Interface (8), (9)
    • DB 에서 조회하는 객체와 Java 프로그램의 객체간에 인터페이스를 정의하는 객체
    • 방법1. Dao 클래스 정의
      • SqlSession 를 직접적으로 사용하는 방법
      • SqlSession 멤버 변수로 사용하며 쿼리파일 수행 요청
// UserDao.java
import org.apache.ibatis.session.SqlSession;
import org.springframework.stereotype.Component;

import com.thesun4sky.querymapper.domain.User;

@Component
public class UserDao {

  // SqlSession 멤버 변수로 사용하며 쿼리파일 수행 요청
  private final SqlSession sqlSession;

  public UserDao(SqlSession sqlSession) {
    this.sqlSession = sqlSession;
  }

  public User selectUserById(long id) {
    return this.sqlSession.selectOne("selectUserById", id);
  }

}

 

  • 장점
    • 쿼리문 실행 전에 넣어줄 매개변수와 쿼리 결과값의 변형을 정의할 수 있다.
    • Namespace를 내 마음대로 둘 수 있다.
    • .xml 파일의 쿼리문 id와 mapper 메소드명을 일치시킬 필요가 없다.
  • 단점
    • Sqlsession 객체를 주입받아야 하며, 쿼리문 실행 시 항상 호출해야 한다.
    • 쿼리문 호출 시 sqlsession에 .xml 파일의 namespce와 쿼리문 id를 매개변수로 넘겨야한다.
  • 방법2. Mapper Interface 정의
    • SqlSession 를 간접적으로 사용하는 방법
    • ibatis 에서 구현해주는 org.apache.ibatis.annotations.Mapper 어노테이션을 사용하면 sqlSession 를 사용하여 자동으로 호출해줌
// UserMapper.java
@Mapper
public interface UserMapper {

  User selectUserById(@Param("id") Long id);

}
  • 장점
    • 메소드의 내부 구현이 불필요하다.
    • Sqlsession 객체 주입이 불펼요하다.
    • .xml 파일의 쿼리문 id와 mapper 메소드 명이 일치한다.
  • 단점
    • .xml의 Namespace가 실제 Mapper.java 위치를 가르켜야 한다.
    • 메소드 내부 정의가 불가능하다.
  • Mapping File (10)
    • SqlSession 가 실행하는 쿼리가 담긴 파일
    • 정의된 인터페이스에 기반해서 수행할 쿼리를 담아두고
    • 쿼리 수행결과를 어떤 인터페이스 매핑할지 정의해놓은 파일
<!-- UserMapper.xml -->
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.thesun4sky.querymapper.mapper.UserMapper">
    <select id="selectUserById" resultType="User">
        select id, name from users where id = #{id}
    </select>
</mapper>

 

 

 

쿼리 코드 만들기 (JpaRepository)

QueryMapper 의 DB의존성 및 중복 쿼리 문제로 ORM 이 탄생했다.

  • ORM 은 DB의 주도권을 뺏어왔다고 표현해도 과언이 아닙니다.
  • ORM 은 DAO 또는 Mapper 를 통해서 조작하는것이 아니라 테이블을 아예 하나의 객체(Object)와 대응시켜 버립니다.
  • 말이 쉽지…. 객체지향(Object) 을 관계형 데이터베이스(Relation) 에 매핑(Mapping) 한다는건 정말 많은 난관이 있습니다.

 

ORM 문제점

문제점  객체의 특징 RDB의 특징 해결방법
상속의 문제 객체 간 상속관계 가능. 테이블 간 상속관계 없음, 독립적으로 존재. - 매핑 정보에 상속 정보 추가.예: @OneToMany, @ManyToOne
관계 문제 객체는 참조를 통해 관계를 가짐.다대다 관계 가능. 외래키(FK)로 관계 설정.다대다 관계는 매핑 테이블 필요. - 매핑 정보에 방향 정보 추가.예: @JoinColumn, @MappedBy
탐색 문제 참조로 객체 탐색 가능.콜렉션 순회 가능. 참조 시 추가 쿼리 또는 Join 발생. - 탐색 시점 관리.예: @FetchType, fetchJoin()
밀도 문제 객체의 멤버 크기가 클 수 있음. 기본 데이터 타입만 존재. - 큰 객체는 테이블로 분리.예: @Embedded
식별성 문제 hashCode 또는 equals() 메서드로 식별. PK로만 식별 가능. - PK를 객체 ID로 설정.예: @Id, @GeneratedValue, EntityManager로 관리.

 

ORM 해결책

  • 영속성 컨텍스트와 쓰기 지연
   
영속성이란? 데이터를 프로그램 종료 후에도 유지하기 위해 DB나 파일에 저장하여 영구적으로 보존하는 특성.
영속성 상태 1. 비영속 (new/transient) : 객체가 영속성 컨텍스트에 포함되지 않은 상태.
2. 영속 (managed) : 객체가 영속성 컨텍스트에 저장되어 관리되는 상태.
3. 준영속 (detached) : 영속성 컨텍스트에서 분리된 상태.
4. 삭제 (removed) : 객체가 삭제되어 영속성 컨텍스트와 DB에서 제거된 상태.
상태 전환 메서드 new > (비영속상태) > persist(),merge() > (영속성 컨텍스트에 저장된 상태) > flush() > (DB에 쿼리가 전송된 상태) > commit() > (DB에 쿼리가 반영된 상태)
쓰기 지연이란? - flush() 호출 전까지 SQL 쿼리를 영속성 컨텍스트에 모아두었다가, 한 번에 DB로 전송하는 최적화 메커니즘.
쓰기 지연 발생 시점 - 트랜잭션 중 객체 생성, 수정, 삭제 시.
- flush() 호출 전까지 쿼리를 최적화하여 보관.
쓰기 지연 효과 - 여러 동작을 모아 쿼리를 한번에 전송하여 최소화.
- 생성/수정/삭제 작업의 중간 상태가 발생하더라도 실제 DB에는 최적화된 쿼리만 전송.
- 불필요한 쿼리 전송 방지.
주의점 - GenerationType.IDENTITY 사용 시, 쓰기 지연이 적용되지 않음.
- 이유: IDENTITY 전략은 키 생성 시점에 단일 쿼리가 필요하며, 외부 트랜잭션 간의 키 중복을 방지하기 위해 즉시 DB에 반영됨.


예제 코드의 흐름

단계  동작 설명
1. 객체 생성 새로운 객체 생성 (new 상태).
2. 엔티티 매니저 생성 영속성 컨텍스트를 관리할 엔티티 매니저 생성.
3. 트랜잭션 시작 데이터의 무결성을 보장하기 위해 트랜잭션 시작.
4. 객체 저장 persist() 호출로 객체를 영속성 컨텍스트에 저장.
5. flush() 호출 영속성 컨텍스트의 SQL 쿼리를 DB로 전송 (commit 시 자동 수행).
6. commit() 호출 DB에 쿼리를 최종 반영.
7. 자원 해제 엔티티 매니저 및 팩토리 자원 반환 (close()).

 

ORM 을 사용하는 가장 쉬운 방법 : JpaRepository

 

💁‍♂️ Repository vs JpaRepository

  • 기존 Repository
    • @Repository 을 클래스에 붙인다.
    • @Component 어노테이션을 포함하고 있어서 앱 실행시 생성 후 Bean으로 등록된다.
    • 앞서배운 Repository 기본 기능만 가진 구현체가 생성된다. (DB별 예외처리 등)
  • 새로운 JpaRepository
    • JpaRepository<Entity,ID> 인터페이스를 인터페이스에 extends 붙인다.
      • @NoRepositoryBean 된 ****상위 인터페이스들의 기능을 포함한 구현체가 프로그래밍된다. (@NoRepositoryBean = 빈생성 막음 →상속받으면 생성돼서 사용가능)
        • JpaRepository (마스터 셰프): 데이터 액세스를 위한 핵심 기능의 종합적인 요리책(기능) 을 제공합니다.
        • @NoRepositoryBean 인터페이스 (셰프): 각 인터페이스는 특정 데이터 액세스 방법을 제공하는 전문적인 기술 또는 레시피를 나타냅니다.
        • JpaRepository 상속: 마스터 셰프의 요리책과 셰프의 전문성을 얻습니다.
      • SpringDataJpa 에 의해 엔티티의 CRUD, 페이징, 정렬 기능 메소드들을 가진 빈이 등록된다. (상위 인터페이스들의 기능) 

 

  • Repository 와 JpaRepository 를 통해 얼마나 간단하게 구현하게 될지 미리 확인해볼까요?
    • Repository 샘플
      • EntityManager 멤버변수를 직접적으로 사용
// UserRepository.java
@Repository
public class UserRepository {

  @PersistenceContext
  EntityManager entityManager;

  public User insertUser(User user) {
    entityManager.persist(user);
    return user;
  }

  public User selectUser(Long id) {
    return entityManager.find(User.class, id);
  }
}
  • JpaRepository 샘플
    • EntityManager 멤버변수를 간접적으로 사용
// UserRepository.java
public interface UserRepository extends JpaRepository<User, Long> {
  // 기본 메서드는 자동으로 만들어짐
}

 

 

테이블 객체 이해하기

도메인 모델과 테이블 설계

더보기

 

도메인 관계 요약 표

도메인  관계 설명 관계 유형
User - 채널과 양방향 관계.- 다른 도메인과 단방향 관계. - User ↔ Channel (양방향).
Channel - 유저와 다대다 관계.- 대화가 이루어지는 채널. - Channel ↔ User (다대다).
Thread - 채널 내 대화 쓰레드.- 댓글(Comment), 이모지(Emotion), 멘션(Mention)과 관계. - Thread ↔ Comment (일대다).- Thread ↔ Emotion (다대다).- Thread ↔ Mention (다대다).
Comment - 쓰레드 내 댓글.- 쓰레드와 다대일 관계.- 이모지(Emotion), 멘션(Mention)과 관계. - Comment ↔ Thread (다대일).- Comment ↔ Emotion (다대다).- Comment ↔ Mention (다대다).
Emotion - 쓰레드, 댓글 내 이모지.- 쓰레드와 댓글 각각과 다대다 관계. - Emotion ↔ Thread (다대다).- Emotion ↔ Comment (다대다).
Mention - 쓰레드, 댓글 내 멘션.- 쓰레드와 댓글 각각과 다대다 관계. - Mention ↔ Thread (다대다).- Mention ↔ Comment (다대다).

관계 예시

  1. User ↔ Channel:
    • 한 명의 유저는 여러 채널에 참여할 수 있고, 한 채널은 여러 유저를 가질 수 있음 (다대다).
  2. Thread ↔ Comment:
    • 한 쓰레드는 여러 댓글을 가질 수 있지만, 댓글은 하나의 쓰레드에만 속함 (다대일).
  3. Thread ↔ Emotion / Comment ↔ Emotion:
    • 여러 이모지가 하나의 쓰레드 또는 댓글에 추가될 수 있고, 하나의 이모지는 여러 쓰레드나 댓글에 사용될 수 있음 (다대다).
  4. Thread ↔ Mention / Comment ↔ Mention:
    • 여러 멘션이 하나의 쓰레드 또는 댓글에 포함될 수 있고, 멘션은 여러 쓰레드나 댓글에서 참조될 수 있음 (다대다).

이 구조는 소셜 미디어나 채팅 애플리케이션에서 자주 볼 수 있는 관계를 모델링합니다.

 

 

Raw JPA 테이블 타입 매핑 기능 

애노테이션  설명  예시 코드
@Entity - 객체 관점에서의 이름.- 기본값으로 클래스명을 사용.- JQL에서 사용되는 이름. @Entity public class User { ... }
@Table - RDB 테이블의 이름을 지정.- @Entity의 이름과 다르게 설정 가능.- SQL에서 사용되는 이름. @Table(name = "users")
@Id - 엔티티의 주 키(Primary Key) 매핑.- 기본 타입(primitive) 및 Date, BigDecimal, BigInteger 사용 가능. @Id private Long id;
@GeneratedValue - 주 키 생성 전략을 지정.- 기본값: AUTO.- 선택 가능: TABLE, SEQUENCE, IDENTITY. @GeneratedValue(strategy = GenerationType.IDENTITY)
@Column - 컬럼 속성 지정.- 주요 옵션: unique, nullable, length, columnDefinition. @Column(name = "email", unique = true, length = 255)
@Temporal - 날짜/시간 타입 매핑.- Date, Calendar 타입만 지원. @Temporal(TemporalType.DATE)
@Transient - 데이터베이스 컬럼으로 매핑하지 않을 필드에 사용. @Transient private String tempData;

 

JPA Anotation 특징 및 활용 요약

애노테이션  특징  활용
@Entity - 클래스가 JPA에서 관리하는 엔티티임을 선언.- 데이터베이스 테이블과 매핑. - JPA가 관리할 객체를 정의할 때 사용.- 예: @Entity public class User { ... }
@Table - 엔티티와 매핑되는 RDB 테이블 이름을 명시적으로 설정.- 생략 시 기본값은 클래스명. - 엔티티 이름과 테이블 이름이 다를 때 사용.- 예: @Table(name = "users")
@Id - 엔티티의 **기본 키(Primary Key)**를 지정. - 필수 설정.- 예: @Id private Long id;
@GeneratedValue - 기본 키의 생성 전략을 지정.- AUTO, IDENTITY, SEQUENCE, TABLE 지원. - 데이터베이스에 적합한 키 생성 방식을 설정.- 예: @GeneratedValue(strategy = GenerationType.IDENTITY)
@Column - 컬럼 속성을 세부적으로 지정.- 주요 속성: unique, nullable, length, columnDefinition. - 컬럼의 제약 조건 설정.- 예: @Column(name = "email", unique = true, nullable = false, length = 255)
@Temporal - 날짜/시간 데이터를 DB에 적합한 타입으로 매핑.- DATE, TIME, TIMESTAMP 지원. - java.util.Date 또는 Calendar 사용 시.- 예: @Temporal(TemporalType.TIMESTAMP)
@Transient - 비영속 필드를 선언.- 해당 필드는 DB에 매핑되지 않음. - DB에 저장되지 않고, 비즈니스 로직에서만 사용되는 데이터 정의.- 예: @Transient private String tempData;

예제 코드

@Entity
@Table(name = "users")
public class User {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Column(name = "email", unique = true, nullable = false, length = 255)
    private String email;

    @Temporal(TemporalType.TIMESTAMP)
    private Date createdAt;

    @Transient
    private String tempData; // DB에 매핑되지 않음
}

 

 

Raw JPA 필드 타입 매핑 기능

구분 설명 관련 애노테이션 예시 코드
기본 타입 - 문자열, 날짜, 불리언 등의 기본 데이터 타입.- 사이즈 제한, 필드명 지정 등 옵션 설정 가능. - @Column- @Enumerated java<br>@Column(name = "email", length = 255)<br>private String email;<br>@Enumerated(EnumType.STRING)<br>private UserType userType;<br>
Composite Value 타입 - 여러 필드를 하나의 값 객체로 묶어 매핑.- 복합 객체를 필드로 적용 가능. - @Embeddable- @Embedded- @AttributeOverrides, @AttributeOverride java<br>@Embeddable<br>public class Address {<br> private String city;<br> private String street;<br>}<br>@Embedded<br>@AttributeOverrides({...})<br>
Collection Value 타입 - 기본 타입 또는 Composite Value 타입의 컬렉션을 매핑.- 주로 @ElementCollection으로 구현. - @ElementCollection java<br>@ElementCollection<br>private List<String> tags = new ArrayList<>();<br>

주요 활용 및 예제

1. 기본 타입 매핑

@Entity
public class User {

    @Id
    @GeneratedValue
    private Long id;

    @Column(name = "email", length = 255, nullable = false)
    private String email;

    @Enumerated(EnumType.STRING) // Enum 값은 STRING으로 매핑
    private UserType userType;
}

2. Composite Value 타입 매핑

@Embeddable
public class Address {
    private String city;
    private String street;
}

@Entity
public class Member {

    @Id
    @GeneratedValue
    private Long id;

    @Embedded
    @AttributeOverrides({
        @AttributeOverride(name = "city", column = @Column(name = "home_city")),
        @AttributeOverride(name = "street", column = @Column(name = "home_street"))
    })
    private Address homeAddress;

    @Embedded
    @AttributeOverrides({
        @AttributeOverride(name = "city", column = @Column(name = "company_city")),
        @AttributeOverride(name = "street", column = @Column(name = "company_street"))
    })
    private Address companyAddress;
}

생성되는 테이블:

CREATE TABLE MEMBER (
  MEMBER_ID BIGINT NOT NULL AUTO_INCREMENT,
  NAME VARCHAR(255) NOT NULL,
  home_city VARCHAR(255) NOT NULL,
  home_street VARCHAR(255) NOT NULL,
  company_city VARCHAR(255) NOT NULL,
  company_street VARCHAR(255) NOT NULL,
  PRIMARY KEY (MEMBER_ID)
);

3. Collection Value 타입 매핑

@Entity
public class Product {

    @Id
    @GeneratedValue
    private Long id;

    @ElementCollection
    @CollectionTable(name = "product_tags", joinColumns = @JoinColumn(name = "product_id"))
    @Column(name = "tag")
    private List<String> tags = new ArrayList<>();
}

생성되는 테이블:

CREATE TABLE product_tags (
  product_id BIGINT NOT NULL,
  tag VARCHAR(255),
  PRIMARY KEY (product_id, tag)
);

특징 및 활용 요약

  • 기본 타입: 일반적인 데이터 저장에 사용되며, 설정 옵션으로 제약조건 지정.
  • Composite Value 타입: 코드의 응집도를 높이고 복합 데이터를 쉽게 관리.
  • Collection Value 타입: 여러 값 관리에 유용하지만, 대규모 데이터에서는 다대일 연관관계를 선호.

 

테이블 객체 만들기

User Entity 만들어보기

  • id, username, password 를 가지는 User Entity 를 만들어 봅니다.
// User.java
// lombok
@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@ToString

// jpa
@Entity
@Table(name = "users")
public class User {

  /**
   * 컬럼 - 연관관계 컬럼을 제외한 컬럼을 정의합니다.
   */
  @Id
  @GeneratedValue(strategy = GenerationType.IDENTITY)
  @Column(name = "id")
  private Long id;

  private String username;

  private String password;

  /**
   * 생성자 - 약속된 형태로만 생성가능하도록 합니다.
   */
  @Builder
  public User(String username, String password) {
    this.username = username;
    this.password = password;
  }

  /**
   * 연관관계 - Foreign Key 값을 따로 컬럼으로 정의하지 않고 연관 관계로 정의합니다.
   */
  @OneToMany
  @Exclude
  private Set<UserChannel> userChannel;

  /**
   * 연관관계 편의 메소드 - 반대쪽에는 연관관계 편의 메소드가 없도록 주의합니다.
   */

  /**
   * 서비스 메소드 - 외부에서 엔티티를 수정할 메소드를 정의합니다. (단일 책임을 가지도록 주의합니다.)
   */
  public void updateUserName(String username) {
    this.username = username;
  }

  public void updatePassword(String password) {
    this.password = password;
  }
}

기타 추천 플러그인

Key PromoterX

  • 단축키 알림

Presentation Assistant

  • 알림 이쁘게 보여주기

 

테이블 객체끼리 관계만들기

 

Raw JPA 연관관계 매핑 기능 요약 표

애노테이션  설명  주요 속성 예시 코드
@OneToOne - 1:1 관계를 매핑.
- 단방향 및 양방향 매핑 가능.- 테이블 분리 여부를 신중히 검토.
- mappedBy: 연관관계 주인 지정.- cascade: 영속성 전이 설정.- fetch: 기본 EAGER. java<br>@OneToOne @JoinColumn(name = "LOCKER_ID") private Locker locker;<br>@OneToOne(mappedBy = "locker") private Member member;<br>
@OneToMany - 1:N 관계를 매핑.
- 단방향 사용 시 비효율적.
- 양방향은 @ManyToOne과 함께 사용.
- mappedBy: 연관관계 주인 필드 지정.- fetch: 기본 LAZY.- cascade: 영속성 전이. java<br>@OneToMany(mappedBy = "parent") private List<Child> childList;<br>@ManyToOne @JoinColumn(name = "parent_id") private Parent parent;<br>
@ManyToOne - N:1 관계를 매핑.
- 가장 많이 사용하는 연관관계.
- JoinColumn과 함께 사용.
- optional: 연관 객체 필수 여부.- fetch: 기본 EAGER, 실무에서는 LAZY 권장.- cascade: 영속성 전이. java<br>@ManyToOne @JoinColumn(name = "parent_id") private Parent parent;<br>
@JoinColumn - 외래키 매핑 시 사용.
- 주로 @ManyToOne과 함께 사용.
- name: 외래키 이름.- referencedColumnName: 참조 대상 컬럼.- unique, nullable, columnDefinition. java<br>@JoinColumn(name = "parent_id") private Parent parent;<br>
@ManyToMany - N:M 관계 매핑.
- 중간 매핑 테이블은 자동 생성.
- 실무에서는 사용을 지양.
- mappedBy: 양방향 매핑 시 주인 지정.- joinTable: 중간 매핑 테이블 이름 지정. java<br>@ManyToMany @JoinTable(name = "parent_child", joinColumns = @JoinColumn(name = "parent_id"), inverseJoinColumns = @JoinColumn(name = "child_id")) private List<Parent> parents;<br>

주요 연관관계 예제

1. @OneToOne 단방향 매핑

@Entity
public class Member {
    @Id
    @GeneratedValue
    private Long id;

    @OneToOne
    @JoinColumn(name = "locker_id")
    private Locker locker;
}

@Entity
public class Locker {
    @Id
    @GeneratedValue
    private Long id;
}

2. @OneToMany와 @ManyToOne 양방향 매핑

@Entity
public class Parent {
    @Id
    @GeneratedValue
    private Long id;

    @OneToMany(mappedBy = "parent")
    private List<Child> childList;
}

@Entity
public class Child {
    @Id
    @GeneratedValue
    private Long id;

    @ManyToOne
    @JoinColumn(name = "parent_id")
    private Parent parent;
}

3. @ManyToMany 매핑

@Entity
public class Parent {
    @Id
    @GeneratedValue
    private Long id;

    @ManyToMany(mappedBy = "parents")
    private List<Child> childs;
}

@Entity
public class Child {
    @Id
    @GeneratedValue
    private Long id;

    @ManyToMany
    @JoinTable(
        name = "parent_child",
        joinColumns = @JoinColumn(name = "parent_id"),
        inverseJoinColumns = @JoinColumn(name = "child_id")
    )
    private List<Parent> parents;
}

실무 권장 사항

  1. @ManyToMany 지양: 중간 매핑 테이블을 직접 정의하여 관리.
  2. fetch 기본값 조정: 대부분의 관계를 LAZY로 설정.
  3. 단방향 vs 양방향: 필요에 따라 양방향 관계를 신중히 설정.

 

 

 

 

 

 

📌 

  •  

 

 

 

📌 

  •  

 

 

 

📌 

  •  

 

 

 

📌 

  •  

 

 

 

📌 

  •  

 

 

 

📌 

  •  

 

 

 

📌 

  •  

 

 

 

📌 

  •  

 

 

 

📌 

  •  

 

 

 

📌 

  •  

 

 


 

 

 🐳 

  •  

 

 

 

 🐳 

  •  

 

 

 

 🐳 

  •  

 

 


 

소제목 

🧩 부모 타입 변수 = 자식 타입 객체; 는 자동으로 부모 타입으로 변환이 일어납니다.

 


 

소제목 

🎵 클래스가 설계도라면 추상 클래스는 미완성된 설계도입니다.

'DB > JPA ( Java Persistence API )' 카테고리의 다른 글

[JPA] SpringData JPA 심화  (0) 2025.01.28
[JPA] 테이블 객체  (0) 2025.01.27
[JPA] 데이터베이스 연결 (Driver)  (1) 2025.01.25
[JPA] JPA와 Transaction  (0) 2025.01.17
[JPA] 지연로딩, 즉시로딩  (0) 2025.01.15

1. 데이터베이스 드라이버의 역할 및 종류

항목 설명 예시/종류
드라이버 역할 애플리케이션과 데이터베이스 간의 통신을 중개. 애플리케이션 요청을 데이터베이스가 이해할 수 있는 언어로 변환. 우체부나 통역사의 역할과 유사.
드라이버 종류 데이터베이스별로 다른 드라이버가 필요. - Oracle: oracle.jdbc.OracleDriver- MySQL: com.mysql.jdbc.Driver- H2: org.h2.Driver


2. 데이터베이스 드라이버 동작 방식

단계 설명 비유
연결 초기화 드라이버가 데이터베이스와 연결. 네트워크 정보, 인증 자격 증명을 사용. 항공기✈️가 관제탑에 이륙 요청.
SQL 전송 및 실행 애플리케이션의 SQL 명령을 데이터베이스가 이해할 수 있도록 변환하여 처리. 외국어를 현지 언어로 번역하는 통역사 역할.
결과 처리 데이터베이스가 반환한 결과를 애플리케이션이 이해할 수 있도록 변환하여 전달. 관제탑이 비행기 착륙을 안전하게 안내.
연결 종료 데이터베이스 연결을 해제하여 자원을 정리하고 시스템 초기화. 항공기✈️가 공항 게이트에 도킹.

[1]. Spring Boot 의 JDBC 라이브러리

  • Spring Boot와 JDBC: Spring Boot는 데이터베이스 연결을 쉽게 구성할 수 있도록 다양한 JDBC 드라이버를 지원합니다. 이를 통해 개발자는 복잡한 설정 없이 데이터베이스와의 연결을 쉽게 구성할 수 있습니다.
  • **spring-boot-starter-jdbc**는 Spring Boot 프로젝트에서 JDBC를 통해 데이터베이스와 상호작용하기 위해 사용되는 스타터 패키지입니다.
    • 이 스타터 패키지는 데이터베이스 작업을 수행하는 데 필요한 주요 의존성과 자동 구성 기능을 제공합니다. 데이터베이스와의 연결을 쉽고 빠르게 구성할 수 있도록 도와주는 브릿지 역할을 합니다.
    • 주요 포함 내용
      1. JDBC API 지원: JDBC API를 통해 SQL 데이터베이스에 접근하고 작업을 수행할 수 있습니다.
      2. DataSource 구성: 데이터 소스 연결을 위한 기본적인 설정을 자동으로 구성합니다. 이는 데이터베이스 연결을 관리하는 데 필수적인 요소입니다.
      3. JdbcTemplate: **JdbcTemplate**은 Spring의 핵심 클래스 중 하나로, JDBC 작업의 많은 번거로움을 줄여 줍니다. SQL 쿼리 실행, 결과 세트 처리, 예외 처리 등을 단순화합니다.
    • 주요 장점 내용
      1. 간소화된 데이터베이스 연결: DataSource 설정과 JdbcTemplate 사용을 통해 복잡한 JDBC 코드를 간소화할 수 있습니다.
      2. 자동 구성: Spring Boot의 자동 구성 기능은 개발자가 데이터베이스 연결에 필요한 대부분의 구성을 자동으로 처리할 수 있도록 합니다.
      3. 효율적인 예외 처리: Spring의 **DataAccessException**을 통해 JDBC에서 발생하는 예외를 Spring의 일관된 예외 체계로 변환합니다.

[2]. JDBC

  • JDBC 드라이버란?: JDBC(Java Database Connectivity)는 자바 애플리케이션에서 데이터베이스에 접근할 수 있도록 하는 API입니다. JDBC 드라이버는 이 API를 구현하여, 자바 애플리케이션과 특정 데이터베이스 간의 연결을 가능하게 합니다.
  • JDBC 드라이버 타입: JDBC 드라이버는 네 가지 유형(Type 1, 2, 3, 4)이 있으며, 각각의 특징과 사용 환경에 따라 선택할 수 있습니다. Type 4 드라이버(순수 자바 드라이버)가 가장 일반적으로 사용됩니다.
  • 문장 그대로 Java 앱과 DB 를 연결시켜주기 위해 만들어진 기술입니다.
  • 그렇기 때문에 JPA 도 이 기술을 사용하여 구현되어 있습니다. ✅
  • JDBC Driver 는 여러타입의 DB 와 연결할 수 있는 기능을 제공합니다.
  • JDBC 실습
    • DriverManager 를 통해서 Connection(연결) 을 생성하여 쿼리를 요청할 수 있는 상태를 만들어주고
    • Statement(상태) 를 생성하여 쿼리를 요청하고
    • ResultSet(결과셋) 을 생성해 쿼리 결과를 받아옵니다.

 

[3]. JDBC Template (QueryMapper)

  • JDBC 로 직접 SQL을 작성했을때의 문제
    • SQL 쿼리 요청시 중복 코드 발생
    • DB별 예외에 대한 구분 없이 Checked Exception (SQL Exception) 처리
    • Connection, Statement 등.. 자원 관리를 따로 해줘야함
      • 자원 해제 안해주면 메모리 꽉차서 서버가 죽음
  • 이 문제 해결을 위해 처음으로 Persistence Framework 등장!
    • Persistence Framework 는 2가지가 있다.
      • SQL Mapper : JDBC Template, MyBatis 👈 요게 먼저나옴
      • ORM : JPA, Hibernate
  • SQL Mapper (QueryMapper)
    • SQL ↔ Object
    • SQL 문과 객체(Object)의 필드를 매핑하여 데이터를 객채화

JDBC Template (RowMapper)

  • SQL Mapper 첫번째 주자로 JDBCTemplate 에 RowMapper 탄생
    • 쿼리 수행 결과와 객채 필드 매핑
    • RowMapper 로 응답필드 매핑코드 재사용
    • Connection, Statement, ResultSet 반복적 처리 대신 해줌
    • 😵‍💫 But, 결과값을 객체 인스턴스에 매핑하는데 여전히 많은 코드가 필요함

3. JDBC 주요 객체 및 역할

객체  역할  사용 예시
Connection 데이터베이스와의 연결을 생성 및 관리. Connection conn = DriverManager.getConnection(url, username, password);
Statement SQL 명령어를 데이터베이스에 전달하는 역할. Statement stmt = conn.createStatement();
PreparedStatement Statement의 확장. 파라미터화된 SQL 쿼리를 효율적으로 실행하며 SQL Injection 방지. PreparedStatement pstmt = conn.prepareStatement("INSERT INTO users VALUES (?, ?)");
ResultSet 쿼리 실행 결과를 저장하고 처리. ResultSet rs = stmt.executeQuery("SELECT * FROM users");

4. JDBC Template 주요 특징

항목  설명
중복 코드 제거 Connection, Statement, ResultSet과 같은 반복적인 코드 제거.
자원 관리 자동화 자원의 자동 반환을 통해 메모리 누수를 방지.
예외 처리 간소화 JDBC의 Checked Exception(SQL Exception)을 Spring의 일관된 예외 체계로 변환.
RowMapper 제공 SQL 결과를 객체와 매핑하는 기능을 제공하여 결과 매핑 코드를 단순화.

5. JDBC Template vs. SQL Mapper vs. ORM

  JDBC Template SQL Mapper (MyBatis 등) ORM (JPA/Hibernate)
주요 특징 SQL 문을 직접 작성하지만 반복적인 작업을 단순화. SQL 문과 객체 필드를 매핑하여 데이터 객체화. 데이터베이스 테이블과 객체 간의 매핑을 자동화.
장점 반복 작업 제거, 코드 간결화. SQL 활용이 유연하며 성능 최적화 가능. 객체 중심의 설계, 개발 생산성 향상.
단점 SQL 코드가 여전히 필요. XML 설정 파일 및 복잡한 매핑 관리가 필요. 초기 학습 곡선이 가파르며 성능 최적화가 어려움.

6. PreparedStatement vs Statement

  Statement  PreparedStatement
SQL Injection 방지 지원하지 않음. 변수 바인딩으로 Injection 방지.
성능 매번 구문 분석(parse) 수행. SQL 구문 분석 결과를 캐싱하여 성능 향상.
사용 방식 SQL 전체를 코드에 작성. SQL에 파라미터를 설정하여 실행.
예시 코드 stmt.executeQuery("SELECT * FROM users WHERE id = " + id); pstmt.setInt(1, id); pstmt.executeQuery();

 

'DB > JPA ( Java Persistence API )' 카테고리의 다른 글

[JPA] 테이블 객체  (0) 2025.01.27
[JPA] 쿼리 파일 만들기 (QueryMapper)  (0) 2025.01.26
[JPA] JPA와 Transaction  (0) 2025.01.17
[JPA] 지연로딩, 즉시로딩  (0) 2025.01.15
[JPA] Proxy  (0) 2025.01.14

+ Recent posts