반응형

https://www.json.org

 

JSON은 오늘날 가장 널리 사용되는 데이터 표현 형식 중 하나다.
REST API, 설정 파일, 로그, 메시지 큐 등 거의 모든 데이터 교환의 기본 단위로 쓰인다.
하지만 JSON이 복잡해질수록, 특정 필드만 찾아내거나 조건에 맞는 데이터를 추출하는 일이 점점 까다로워진다.

이럴 때 유용하게 쓸 수 있는 기술이 바로 JSONPath다.
SQL이 데이터베이스에서 원하는 값을 추출하는 질의 언어라면 JSONPath는 JSON 문서 안에서 값을 찾아내는 경로 질의 언어다.


JSONPath란 무엇인가

JSONPath는 JSON 데이터를 탐색하기 위한 표현식 언어다.
XPath가 XML을 탐색하듯이 JSONPath는 JSON의 계층 구조를 탐색한다.

간단히 말해,

  • $.store.book[0].title → 루트($)에서 store → book 배열 → 첫 번째 객체의 title 값을 가져온다.
  • $.store.book[*].author → 모든 책 객체의 author 필드를 반환한다.

이처럼 JSONPath는 중첩된 구조를 쉽게 탐색할 수 있도록 도와준다.


JSONPath 문법 요약

Expression Description
$ 루트 객체
@ 현재 노드
. 또는 [] 하위 요소 접근
* 모든 요소 선택
[n] n번째 요소 선택 (0부터 시작)
[start:end] 슬라이스 선택
?() 조건 필터링
, 여러 항목 선택

예를 들어, 다음 JSON 데이터가 있다고 하자.

{
  "store": {
    "book": [
      { "category": "fiction", "title": "1984", "price": 8.99 },
      { "category": "fiction", "title": "Animal Farm", "price": 5.99 },
      { "category": "non-fiction", "title": "Sapiens", "price": 12.99 }
    ],
    "bicycle": { "color": "red", "price": 19.95 }
  }
}

여기서 다음과 같은 질의가 가능하다.

JSONPath Result
$.store.book[*].title ["1984", "Animal Farm", "Sapiens"]
$.store.book[?(@.price < 10)].title ["1984", "Animal Farm"]
$..price [8.99, 5.99, 12.99, 19.95]
$.store..price 동일 결과 (..은 중첩된 모든 price 탐색)

조건식과 연산자

JSONPath의 강력한 기능 중 하나는 조건식(?())을 통한 필터링이다.
@는 현재 노드를 가리키며, 비교 연산자나 논리 연산자와 함께 사용할 수 있다.

Operator Description Example
<, <=, >, >=, ==, != 비교 연산 @.price < 10
&&, || 논리 연산 @.price < 10 && @.category == 'fiction'
=~ 정규식 일치 @.title =~ /.*Farm.*/

예시:

$.store.book[?(@.price < 10 && @.category == 'fiction')].title

→ ["1984", "Animal Farm"]

이런 필터는 JSON을 순회하지 않고도 필요한 데이터만 추출할 수 있게 해 준다.

중첩 탐색(..)

.. 연산자는 JSON의 모든 하위 노드를 깊이 탐색한다.
예를 들어, $.store..price는 store 내부의 모든 price 필드를 반환한다.
중첩된 구조에서 특정 키를 전역 검색하듯 사용할 수 있어,
API 응답처럼 깊은 계층을 가진 JSON을 다룰 때 매우 유용하다.


JSONPath의 장점

  1. 간결한 탐색 표현
    중첩 구조를 단 한 줄의 경로 표현식으로 접근할 수 있다. 기존에는 key 값으로 중첩된 JSON Object를 하나씩 끌어내어 값을 가져와야 했다면 JSON Path를 이용하면 중첩된 모든 JSON Object에 접근하지 않아도 간결하게 값을 찾을 수 있다.
  2. 조건 필터링 지원
    단순 값을 가져오는 표현식이 아니고 조건을 함께 명시하여 값을 가져올 수 있다. 기존에는 JSON Object를 순회하며 if 문을 이용해 필터링하였지만 JSON Path의 조건 필터링을 이용하면 한 줄로 필터링과 동시에 값을 가져올 수도 있다.
  3. 언어 독립성
    JSONPath는 특정 언어에 종속되지 않으며, Java, Python, Go, JavaScript 등에서 동일한 문법으로 사용할 수 있다.
  4. 효율적인 데이터 접근
    전체 JSON을 순회할 필요 없이 필요한 경로만 탐색한다.

Java에서의 JSONPath 사용

JSON Path를 자바에서 실제로 사용해보고자 한다.

 

Java에서는 일반적으로 Jayway JSONPath 라이브러리를 사용한다.

 

게시글 작성일(2025. 11. 04) 기준 최신 버전인 2.10.0 버전을 사용하였다.

 

build.gradle 파일에 json-path 라이브러리를 추가한다.

dependencies {
	implementation 'com.jayway.jsonpath:json-path:2.10.0'
}

 

메인 메서드는 아래와 같이 작성하였다.

import com.jayway.jsonpath.JsonPath;
import java.util.List;

public class JsonPathExample {
    public static void main(String[] args) {
        String json = """
            {
              "store": {
                "book": [
                  { "category": "fiction", "title": "1984", "price": 8.99 },
                  { "category": "fiction", "title": "Animal Farm", "price": 5.99 },
                  { "category": "non-fiction", "title": "Sapiens", "price": 12.99 }
                ],
                "bicycle": { "color": "red", "price": 19.95 }
              }
            }
        """;

        List<String> titles = JsonPath.read(json, "$.store.book[*].title");
        System.out.println("모든 책 제목: " + titles);

        List<String> cheapBooks = JsonPath.read(json, "$.store.book[?(@.price < 10)].title");
        System.out.println("저렴한 책: " + cheapBooks);

        List<Double> prices = JsonPath.read(json, "$..price");
        System.out.println("가격 목록: " + prices);
    }
}

 

실행 결과는 아래와 같다.

모든 책 제목: [1984, Animal Farm, Sapiens]
저렴한 책: [1984, Animal Farm]
가격 목록: [8.99, 5.99, 12.99, 19.95]

 

반응형
반응형

웹 개발을 배우다 보면 HTML과 XML이 서로 닮았다는 인상을 받는다.
둘 다 "<"과 ">"로 둘러싸여 있는 태그로 이루어져 있고, 중첩 구조를 가지며, 계층적으로 데이터를 표현한다.
하지만 이 둘은 같은 조상으로부터 태어났을 뿐, 완전히 다른 목표를 향해 발전했다.
이 공통의 조상이 바로 SGML(Standard Generalized Markup Language)이다.


SGML이란

SGML은 1986년에 ISO에서 표준화된 문서 구조 정의 언어다.
당시 목적은 “다양한 문서 형식을 일관되게 표현할 수 있는 일반 규칙”을 만드는 것이었다.
즉, HTML이나 XML처럼 특정 문서를 직접 표현하는 언어가 아니라,
‘마크업 언어를 만들기 위한 언어’, 일종의 메타언어(meta-language)였다.

SGML의 기본 철학은 다음과 같다:

  1. 문서의 구조와 의미를 분리한다.
    데이터의 ‘형식’과 ‘표현’을 명확히 구분
  2. 문법을 정의할 수 있는 틀을 제공한다.
    DTD(Document Type Definition)로 각 언어의 문법을 기술
  3. 플랫폼 독립적 구조화
    시스템이 달라도 같은 규칙으로 문서를 읽을 수 있게 설계

이 구조적 유연성이 이후 HTML과 XML로 이어지게 된다.


HTML과 XML

HTML: 사람이 읽는 방향으로 단순화

1990년대 초, 팀 버너스리가 웹을 설계하면서 SGML을 기반으로 HTML(HyperText Markup Language)을 만들었다.
웹 브라우저에서 쉽게 표시할 수 있도록 SGML의 복잡한 구조를 대폭 단순화한 형태였다.

  • SGML의 문법적 엄격함을 완화
  • 렌더링 중심 (시각적 표시를 우선)
  • 브라우저가 오류를 자동 보정하도록 설계

즉, SGML의 “표현은 단순하게, 의미는 최소한만” 철학을 취한 것이다.

XML: 기계가 이해하는 방향으로 정제

반면, 1998년 W3C는 SGML을 간소화하면서도 데이터의 구조적 엄밀함을 유지한 XML(eXtensible Markup Language)을 표준화했다.
XML은 “SGML의 정신을 계승하되, 현대 시스템 환경에 맞게 단순화한 구조적 언어”라고 할 수 있다.

  • SGML의 복잡한 옵션 제거
  • DTD와 유사한 구조 검증 기능 유지
  • 태그, 속성, 문법을 모두 엄격하게 제한

이 결과, XML은 웹 브라우저보다는 데이터 교환, 설정 파일, API 응답 등에서 활발히 쓰이게 되었다.

항목 HTML XML
성격 SGML 파생 문서 언어 SGML 경량화 문서 언어
주요 목적 시각적 표현 데이터 교환
에러 허용 허용 불허
대표 사용처 웹페이지 RSS, 설정파일, SOAP

 

반응형
반응형

개요

protoc은 Google의 Protocol Buffers(.proto 파일)를 컴파일해 언어별 소스 코드를 생성하는 도구다.
패키지 관리자에 포함된 버전은 종종 구버전이므로, 공식 GitHub 릴리즈에서 직접 설치하는 게 안전하다.


준비

unzip과 wget이 없으면 먼저 설치한다.

sudo apt update && sudo apt install -y wget unzip

(RHEL·Rocky Linux 계열이라면 sudo yum install -y wget unzip)

 


다운로드

protobuf은 아래 링크에서 확인할 수 있다. 현재일(2025년 11월 1일) 기준 v33.0 버전이 최신 버전이다.

 

Releases · protocolbuffers/protobuf

Protocol Buffers - Google's data interchange format - protocolbuffers/protobuf

github.com

파일은 자신의 운영체제와 아키텍처에 맞게 다운로드 받으면 된다.

 

필자는 Linux 운영체제 x86_64 아키텍처 전용 파일을 받기 위해 링크를 복사한다.

wget https://github.com/protocolbuffers/protobuf/releases/download/v33.0/protoc-33.0-linux-x86_64.zip

 

wget 명령어로 해당 파일을 다운로드 받는다.

 

unzip protoc-33.0-linux-x86_64.zip -d $HOME/.local/protoc

 

홈 디렉터리 내에 .local/protoc 디렉토리로 압축을 해제한다.

 

.local/
 └── protoc
     ├── bin/
     │   └── protoc
     └── include/
         └── google/
             └── protobuf/

 

그러면 홈 디렉토리 아래에 위와 같은 파일 구조가 생성된다.

 

이제 설치된 protoc를 터미널에서 바로 사용할 수 있도록 환경변수를 등록해주어야 한다.


환경 변수 등록

PATH에 protoc 경로를 추가한다.

bash를 기본쉘로 사용하고 있다면

echo 'export PATH="$PATH:$HOME/.local/protoc/bin"' >> ~/.bashrc
source ~/.bashrc

zsh를 기본쉘로 사용하고 있다면

echo 'export PATH="$PATH:$HOME/.local/protoc/bin"' >> ~/.zshrc
source ~/.zshrc

로 환경변수를 추가하고 적용한다.


설치 확인

아래 명령어를 입력하여 protocol buffer가 정상적으로 설치됐는지 확인할 수 있다.

protoc --version

아래와 같이 설치한 버전이 나타나면 정상적으로 설치가 된 것이다.

libprotoc 33.0

 

반응형
반응형

https://grpc.io/

gRPC의 등장 배경

마이크로서비스 아키텍처(MSA)가 대세가 되면서, 시스템은 하나의 거대한 모놀리식 구조에서 수많은 독립적인 서비스로 쪼개지게 되었다. 이러한 서비스들은 서로 데이터를 교환하고 요청을 주고받아야 하는데, 이를 위해 등장한 기술이 바로 gRPC다.

 

기존에는 REST API가 대표적인 통신 방식이었다. REST는 HTTP 기반으로 작동하며, JSON 포맷을 주로 사용하기 때문에 가독성이 좋고 디버깅이 쉬웠다. 하지만 REST에는 성능적인 한계가 존재했다. JSON은 텍스트 기반 포맷이라 직렬화(serialize) 및 역직렬화(deserialize) 비용이 크고, 대규모 서비스 간 통신에서는 네트워크 비용이 누적되어 병목이 발생한다.

 

특히 대량의 요청을 빠르게 주고받아야 하는 실시간 시스템이나 양방향 스트리밍이 필요한 서비스에서는 REST의 한계가 뚜렷했다. 이러한 문제를 해결하기 위해 Google이 개발한 것이 gRPC (Google Remote Procedure Call)이다.


gRPC란?

gRPC는 Google이 개발한 오픈소스 원격 프로시저 호출(Remote Procedure Call, RPC) 프레임워크다. RPC란 간단히 말해 “네트워크를 통한 함수 호출”이다. 즉, 다른 서버의 함수를 로컬 함수처럼 호출할 수 있게 해주는 기술이다.

 

gRPC는 Google의 내부 통신 프레임워크인 Stubby를 오픈소스로 공개한 프로젝트로, 효율성, 속도, 유연성에 초점을 맞추고 있다. REST와 달리, gRPC는 바이너리 기반의 통신을 사용하기 때문에 데이터 전송량이 훨씬 적고, 성능이 탁월하다.

 

RPC의 핵심은 HTTP/2Protocol Buffers(ProtoBuf)에 있다.

  • HTTP/2 기반 통신
    • 하나의 TCP 연결 위에서 다중 스트림(multiplexing)을 지원하여 여러 요청을 동시에 처리할 수 있다.
    • 헤더 압축(Header Compression)으로 네트워크 오버헤드를 줄인다.
    • 서버 푸시(Server Push)를 지원해 실시간 알림 등에 유리하다.
  • Protocol Buffers (protobuf)
    • Google이 개발한 직렬화 포맷으로, JSON보다 훨씬 빠르고 용량이 작다.
    • .proto 파일을 작성해 데이터 구조(메시지)와 서비스 인터페이스를 정의한다.
    • 각 언어별로 자동으로 코드가 생성되어, 클라이언트와 서버가 동일한 인터페이스를 공유할 수 있다.

이 두 가지 덕분에 gRPC는 REST보다 빠르고 효율적이며, 명확한 타입 안전성을 제공한다.


gRPC의 통신 방식

gRPC는 4가지 유형의 통신 모델을 지원한다.

1. Unary RPC (단일 요청/응답)

 

  • 가장 기본적인 형태로, 클라이언트가 한 번 요청하고 서버가 한 번 응답한다.
  • REST의 일반적인 요청-응답 패턴과 동일하다.
+-----------+                       +-----------+
|  Client   |                       |  Server   |
+-----------+                       +-----------+
      |                                   |
      |   ① Request (HelloRequest)       |
      |---------------------------------->|
      |                                   |
      |   ② Response (HelloResponse)     |
      |<----------------------------------|
      |                                   |

 

2. Server Streaming RPC (서버 스트리밍)

 

  • 클라이언트가 한 번 요청하면, 서버가 여러 개의 응답을 스트림 형태로 전송한다.
  • 예: 실시간 로그 스트리밍, 파일 다운로드
+-----------+                       +-----------+
|  Client   |                       |  Server   |
+-----------+                       +-----------+
      |                                   |
      |   ① Request (GetLogsRequest)     |
      |---------------------------------->|
      |                                   |
      |   ② Stream of Responses          |
      |<--------- LogEntry #1 ------------|
      |<--------- LogEntry #2 ------------|
      |<--------- LogEntry #3 ------------|
      |<---------   (complete)   ---------|
      |                                   |

 

3. Client Streaming RPC (클라이언트 스트리밍)

 

  • 클라이언트가 여러 개의 요청을 스트림으로 보내고, 서버가 한 번 응답한다.
  • 예: IoT 디바이스에서 다량의 센서 데이터를 서버로 보낼 때
+-----------+                       +-----------+
|  Client   |                       |  Server   |
+-----------+                       +-----------+
      |                                   |
      |   ① Stream of Requests           |
      |--- SensorData #1 ---------------->|
      |--- SensorData #2 ---------------->|
      |--- SensorData #3 ---------------->|
      |---   (end of stream)   ---------->|
      |                                   |
      |   ② Response (SummaryResponse)   |
      |<----------------------------------|
      |                                   |

 

4. Bidirectional Streaming RPC (양방향 스트리밍)

 

  • 클라이언트와 서버가 모두 스트림 형태로 데이터를 주고받는다.
  • 실시간 채팅, 주가 데이터, 게임 서버 등에서 사용된다.
+-----------+                       +-----------+
|  Client   |                       |  Server   |
+-----------+                       +-----------+
      |                                   |
      |<------ Response #1 ---------------|
      |--- Request #1 ------------------->|
      |<------ Response #2 ---------------|
      |--- Request #2 ------------------->|
      |<------ Response #3 ---------------|
      |--- Request #3 ------------------->|
      |--- (stream end) ----------------->|
      |<------ (stream end) --------------|
      |                                   |

gRPC의 현재 활용 현황

gRPC는 대규모 마이크로서비스 아키텍처(MSA) 환경에서 광범위하게 사용되고 있다.
대표적인 사례로는 다음과 같다:

  • Google Cloud, Kubernetes: 내부 서비스 간 통신에 gRPC를 사용.
  • Netflix, Square, Cisco: 고성능 분산 서비스의 백엔드 통신에 활용.
  • TensorFlow Serving: 모델 서빙 API가 gRPC 기반으로 동작.
  • Istio, Envoy: 서비스 메시의 제어 평면(Control Plane) 통신에도 사용.

Go, Java, Python, C#, C++, Node.js 등 다양한 언어에서 공식적으로 지원되며, 언어 간 상호 운용성(interoperability)이 뛰어나다는 점이 큰 장점이다.


gRPC 예제

이제 Go를 이용해 간단한 gRPC 서버와 클라이언트를 만들어보자.

(1) .proto 파일 정의

syntax = "proto3";

package greet;
option go_package = "example.com/grpc/greetpb";

service GreetService {
  rpc SayHello (HelloRequest) returns (HelloResponse);
}

message HelloRequest {
  string name = 1;
}

message HelloResponse {
  string message = 1;
}

(2) 코드 생성

터미널에서 다음 명령을 실행한다. 만약 protoc 명령어를 사용할 수 없다면 [ 이 게시글 ]을 참고하여 설치할 수 있다.

protoc --go_out=. --go-grpc_out=. greet.proto

이 명령은 Go용 gRPC 인터페이스 및 메시지 구조체를 자동 생성한다.

(3) gRPC 관련 패키지 설치

go 프로젝트 디렉터리에서 다음 명령을 실행하여 gRPC 관련 패키지를 설치한다.

go get google.golang.org/grpc
go get google.golang.org/protobuf

(4) 서버 구현 (server.go)

package main

import (
    "context"
    "fmt"
    "log"
    "net"

    "google.golang.org/grpc"
    "example.com/grpc/greetpb"
)

type server struct {
    greetpb.UnimplementedGreetServiceServer
}

func (s *server) SayHello(ctx context.Context, req *greetpb.HelloRequest) (*greetpb.HelloResponse, error) {
    name := req.GetName()
    message := fmt.Sprintf("안녕하세요, %s님!", name)
    return &greetpb.HelloResponse{Message: message}, nil
}

func main() {
    lis, err := net.Listen("tcp", ":50051")
    if err != nil {
        log.Fatalf("리슨 실패: %v", err)
    }

    grpcServer := grpc.NewServer()
    greetpb.RegisterGreetServiceServer(grpcServer, &server{})

    log.Println("gRPC 서버 실행 중... 포트: 50051")
    if err := grpcServer.Serve(lis); err != nil {
        log.Fatalf("서버 실패: %v", err)
    }
}

 

(5) 클라이언트 구현 (client.go)

package main

import (
    "context"
    "log"
    "time"

    "google.golang.org/grpc"
    "example.com/grpc/greetpb"
)

func main() {
    conn, err := grpc.Dial("localhost:50051", grpc.WithInsecure())
    if err != nil {
        log.Fatalf("연결 실패: %v", err)
    }
    defer conn.Close()

    client := greetpb.NewGreetServiceClient(conn)
    ctx, cancel := context.WithTimeout(context.Background(), time.Second)
    defer cancel()

    res, err := client.SayHello(ctx, &greetpb.HelloRequest{Name: "테스트"})
    if err != nil {
        log.Fatalf("요청 실패: %v", err)
    }

    log.Printf("응답: %s", res.GetMessage())
}

 

서버를 실행한 뒤 클라이언트를 실행하면 콘솔에 다음과 같은 결과가 출력된다.

응답: 안녕하세요, 테스트님!

이 간단한 예시가 보여주듯, gRPC를 사용하면 마치 로컬 함수 호출처럼 원격 서버의 메서드를 호출할 수 있다.


gRPC는 단순히 “빠른 REST 대체재”가 아니다.
양방향 스트리밍, 효율적인 직렬화, 명확한 인터페이스 정의, 언어 간 호환성 덕분에, 앞으로도 대규모 분산 시스템의 표준 통신 방식으로 자리 잡을 가능성이 크다.

또한 HTTP/3 기반 QUIC 프로토콜과의 통합도 활발히 논의되고 있어, gRPC는 더욱 저지연(low-latency) 환경에서도 활용될 전망이다.

REST가 웹 API의 표준이라면, gRPC는 MSA와 실시간 분산 시스템의 표준이라 할 수 있다.

반응형
반응형

필자는 회사에서 업무 특성 상 다양한 데이터베이스를 사용하고 소프트웨어 개발 배포를 Docker로 하기 때문에 Docker의 사용이 필수적이다. Docker Desktop을 사용하면 되는 것이 아닌가 싶지만 Docker Desktop은 일정 수익 이상을 내고 있는 회사에서 업무용으로는 라이선스 상 사용이 불가하다. 그렇기 때문에 WSL을 설치하고 그 위에 Docker CLI를 설치하여 사용하여야 한 것이다. 기존에는 C드라이브 하나만 사용했어서 WSL을 C 드라이브에 설치하면 되기 때문에 아무런 문제가 없었지만, 최근 컴퓨터를 포맷하면서 C 드라이브와 D 드라이브로 파티션을 분할하였고 C는 운영체제와 필수 프로그램만 들어갈 정도로 용량이 작아지면서 큰 용량의 프로그램이나 업무 파일들은 D 드라이브에 저장하여야 했다.

 

그런데 Powershell이나 Microsoft Store에서 wsl을 설치하게 하면 C드라이브에 설치를 강제한다. 여럿 글을 찾아보니 C 드라이브에 일단 설치하고 D 드라이브로 옮기는 방법을 설명하고 있던데 필자는 그것도 못한다.

용량이 아주 처참하기 때문에 D 드라이브에 다이렉트로 설치하는 방법이 필요했고 다행히도 WSL을 수동으로 설치할 수 있도록 방법을 제공하고 있었다.

 

설치 준비

설치하고 싶은 리눅스 배포판을 아래 링크에서 다운로드한다.

 

이전 버전의 WSL에 대한 수동 설치 단계

wsl install 명령을 사용하는 대신 이전 버전의 Windows에 WSL을 수동으로 설치하는 단계별 지침입니다.

learn.microsoft.com

필자는 Ubuntu 24.04 버전으로 진행할 것이다.

클릭하게 되면 아래와 같이 .AppxBundle 이라는 확장자로 파일이 다운로드된다.

 

이 파일의 확장자를 .zip 으로 변경해준다.

이렇게 압축파일로 변경해서 압축을 풀고 내부를 확인해보면 다양한 appx 파일이 보이는데 여기서 주목할 것은 “_ARM64”, “_x64”로 끝나는 파일들이다. 자신 컴퓨터에 맞게 사용하면 된다. 만약, 자신의 컴퓨터 아키텍처를 잘 모른다면 [여기] 에서 안내하는 방법으로 확인이 가능하다.

자신의 컴퓨터 아키텍처에 맞는 appx 파일을 아까와 동일하게 .zip 확장자로 변경하여 압축을 해제한다.

그러면 위와 같이 파일들이 보이는데 이 파일들 중 install.tar.gz 파일만 사용할 것이다.

이제 원하는 경로에 설치를 해보자.

설치

wsl --import [wsl이름(자유)] [설치경로] [install.tar.gz파일경로]

위 명령어를 사용하면 된다. 필자는 install.tar.gz를 “D:\WSL” 폴더에 옮겨놓았고 “D:\WSL” 폴더 안에 wsl 이름의 폴더를 생성하여 설치되도록 할 것이다.

wsl --import ubuntu24.04 "D:\WSL\ubuntu-24.04" "D:\WSL\install.tar.gz"

하지만 오류가 나왔는데 필자는 컴퓨터를 포맷하고 WSL을 설치하지 않았었기에 WSL 설치가 먼저 진행되었다. 다만, WSL 설치는 컴퓨터를 재부팅하여야 완료되는 것이였기 때문에 재부팅하기 전까지는 install.tar.gz를 설치할 수 없었다. 이 상태에서 재부팅하여 다시 명령어를 실행하여 설치하였다.

재부팅 후 다시 명령어를 실행하니 위 사진처럼 “D:\WSL\ubuntu-24.04” 폴더 내에 가상 드라이브 파일이 생성되었다. 이제 powershell에서 wsl에 접속해보자.

wsl

잘 접속되는 것을 확인할 수 있다.

반응형
반응형

소프트웨어 설치 프로그램을 보면 x86, x64, arm64처럼 CPU 아키텍처별로 따로 제공되는 경우가 많다. 개인용 컴퓨터라면 내가 어떤 CPU 아키텍처를 쓰는지 쉽게 알 수 있지만, 공용 컴퓨터나 가상머신(VM) 환경에서는 따로 확인해야 하는 경우가 있다. 이번 글에서는 Windows와 Unix 계열(Linux, macOS)에서 CPU 아키텍처를 확인하는 방법을 정리한다.

 

1. Windows에서 CPU 아키텍처 확인하기

1) Win + R 키를 눌러 실행 창을 연다.

2) msinfo32 입력 후 실행한다.

3) 시스템 요약 → 시스템 종류 항목 확인

  • x64 기반 PC → 64비트(x64) 아키텍처이다.
  • x86 기반 PC → 32비트(x86) 아키텍처이다.
  • ARM 기반 PC → ARM 아키텍처이다.

2. Linux / macOS에서 CPU 아키텍처 확인하기

1) 터미널을 연다.

2) uname 명령어를 입력한다.

uname -m

 

  • x86_64 → 64비트(x64) 아키텍처 ( Apple의 경우 Intel Mac )
  • i686, i386 → 32비트(x86) 아키텍처
  • arm64, aarch64 → ARM64 아키텍처 ( Apple의 경우 Apple Silicon )

 

 

반응형
반응형

 

프로그래밍을 한다고 하면 다 알법한 ASCII 코드표이다.

물론 전부를 외우라는 사람은 없을 것이고 외우고 있는 사람 또한굉장히 드물것이다.

하지만 숫자는 48~57, 영대문자는 65 ~ 90, 영소문자는 97 ~ 122 라는 정도만 기억해도 굉장히 유용할 것이다.
ASCII 는 American Standard Code For Infomation Interchange 라는 정보 교환을 위한 미국 표준 코드 약자이다.
ANSI에서 표준 코드 체계를 제안하고 국제 부호 체계가 되었다.

이 ASCII 코드는 각 문자를 7비트로 표현하므로 27 개 즉128개의 문자를 표현할 수 있다.
이 ASCII 코드의 단점은 영어 말고 다른 언어 문자는 표현할 수 없다는 큰 단점을 가지고 있는데, 이런 큰 단점을 해결한 코드가 유니코드이다.

 

반응형
반응형

Java 진영에서 ORM(Object Relational Mapping)을 구현할 때 가장 많이 사용하는 기술은 단연 JPA(Java Persistence API)다. JPA를 제대로 이해하려면 우선 엔티티(Entity)가 어떤 생명주기를 거치는지 알아야 한다.

이 글에서는 JPA 엔티티의 생명주기를 단계별로 살펴보고, 각 단계에서 어떤 동작이 일어나는지 정리한다.


1. 엔티티의 상태

JPA에서 엔티티는 단순히 데이터베이스의 한 레코드(row)와 매핑되는 객체가 아니다. 엔티티는 영속성 컨텍스트(Persistence Context)라는 특별한 캐시와 밀접하게 연관되어 작동한다.

즉, 엔티티는 단순히 생성 → 사용 → 삭제의 흐름이 아니라 영속성 컨텍스트에 관리되느냐 아니냐에 따라 네 가지 상태를 오가게 된다.


(1) 비영속 (Transient)

  • 아직 영속성 컨텍스트와 관계없는 상태
Member member = new Member("kim"); // 비영속 상태
  • 단순히 new로 만든 객체일 뿐, DB와 아무 상호작용도 하지 않은 상태를 말한다.

(2) 영속 (Persistent)

  • 영속성 컨텍스트가 관리하는 상태
em.getTransaction().begin();
Member member = new Member("kim"); // 아직 member는 Transient
em.persist(member); // 이제 member는 Persistent
em.getTransaction().commit();
  • 이 상태에서 엔티티는 1차 캐시에 저장된다.
  • 트랜잭션 커밋 시점에 DB에 반영된다.

(3) 준영속 (Detached)

  • 영속성 컨텍스트에서 분리된 상태
Member member = em.find(Member.class, 1L);
em.detach(member); // 준영속 상태
member.setName("park");
em.getTransaction().commit(); // UPDATE 없음
  • em.clear() 또는 em.close() 호출 시에도 전체 엔티티가 준영속 상태가 됩니다.
  • 다시 em.merge()로 영속 상태로 되돌릴 수 있다.

(4) 삭제 (Removed)

  • 삭제가 예약된 상태
Member member = em.find(Member.class, 1L);
em.remove(member); // 삭제 상태
em.getTransaction().commit();

2. 변경 감지 (Dirty Checking)

네 가지 상태 중에서 영속 상태일 때만 적용되는 중요한 기능이 있다. 바로 **변경 감지(Dirty Checking)**다.

일반적으로 JPA에서는 persist, find, remove로 저장, 조회, 삭제는 지원하지만 update 즉, 수정은 메서드로 존재하지 않는다. 이때 변경 감지 기능을 사용하여 update를 구현할 수 있다.

em.getTransaction().begin();
Member member = em.find(Member.class, 1L);
member.setName("lee");
em.getTransaction().commit();
  • JPA는 트랜잭션 커밋 시점에 1차 캐시 스냅샷과 엔티티의 현재 값을 비교한다.
  • 변경된 값이 있으면 자동으로 UPDATE SQL을 실행한다.

3. 정리

  • JPA Entity는 비영속(Transient), 영속(Persistent), 준영속(Detached), 삭제(Removed)와 같은 상태를 가진다.
  • 상태 전환은 persist(), detach(), merge(), remove() 같은 메서드로 제어할 수 있다.
  • 영속 상태에서는 변경 감지가 적용되어, 엔티티 내부의 값만 수정해도 자동으로 DB에 반영된다.

따라서 JPA를 사용할 때는 단순히 객체를 다룬다고 생각하기보다 지금 이 엔티티가 JPA 입장에서 어떤 상태인가를 항상 의식하고 사용하는 것이 중요하다.

반응형

+ Recent posts