사전 엔티티
용어함정

엔티티

gabury1고친 사람 github-actions[bot]

엔티티는 시스템이 하나씩 따로 알아보고 기록해 두는 대상을 가리킵니다. 데이터베이스 설계에서는 고객 한 명이나 주문 한 건이 엔티티입니다. 그런데 태그로 적는 문서에서는 < 처럼 & 로 시작하는 이름으로 불러 끼워 넣는 글 조각을 엔티티라고 합니다. 같은 낱말이 분야마다 다른 것을 가리켜서 어느 쪽 이야기인지부터 가려야 합니다.

쉽고 빠른 이해

무슨 일을 하는 말인가 — 따로 알아보고 기록해 둘 대상 하나를 가리킵니다. 쇼핑몰이라면 고객 한 명, 주문 한 건, 상품 하나가 각각 엔티티입니다.

왜 정해 두나 — 고객을 따로 떼어 두지 않으면 주문마다 고객 이름과 주소를 되풀이해 적게 됩니다. 주소가 바뀌면 그 주문들을 전부 찾아 고쳐야 합니다. 대상을 먼저 나눠 두면 같은 사실을 한 곳에만 적습니다.

어떻게 도나

  1. 다룰 대상을 고객·주문·상품 같은 종류로 나눕니다
  2. 종류마다 적을 값과, 하나를 다른 하나와 가려낼 번호를 정합니다
  3. 고객이라는 종류는 표 하나가 됩니다. 고객 한 명은 그 표의 한 줄이 됩니다
  4. 코드에서는 그 한 줄을 객체 하나로 옮겨 다룹니다

헷갈리는 점 — 태그로 적는 문서 안의 엔티티는 이 뜻과 상관이 없습니다. 이름을 불러 끼워 넣는 글 조각을 가리킵니다. &lt; 라고 적으면 < 가 끼워 들어가는 것이 그 예입니다.

대가 — 대상을 잘게 나눌수록 한 번에 보려면 여러 표를 이어 붙여야 합니다. 나눈 방식을 나중에 바꾸려면 쌓인 데이터까지 옮겨야 합니다.

상세

먼저 「엔티티」가 가리키는 뜻들을 표 하나로 가릅니다. 그다음 백엔드 개발자가 가장 자주 만나는 뜻을 쇼핑몰의 고객과 주문으로 따라갑니다. 데이터를 어떤 덩어리로 나눠 담을지 정하는 데이터 모델링의 엔티티입니다. 그 엔티티가 표와 코드로 옮겨지는 모습을 본 뒤, 줄기가 다른 두 뜻을 차례로 봅니다. 끝에서는 어느 뜻인지 가르는 단서를 모읍니다.

엔티티가 가리키는 뜻들

맥락마다 엔티티가 무엇을 가리키는지 모았습니다. 셋째 줄의 XML(Extensible Markup Language, 확장 가능 마크업 언어)은 태그로 데이터를 적는 텍스트 형식입니다. 넷째 줄의 HTTP(HyperText Transfer Protocol)는 웹에서 요청과 응답을 주고받는 규칙입니다.

맥락 엔티티가 가리키는 것 예
데이터 모델링 따로 알아보고 기록해 둘 대상 고객 · 주문 · 상품
애플리케이션 코드 데이터베이스 표의 한 줄과 짝을 이루는 객체 고객 한 명을 담은 고객 객체
XML 문서 이름을 붙여 두고 불러 쓰는 글 조각 &lt; 를 적으면 < 가 들어간다
HTTP 메시지 요청이나 응답에 실려 오가는 내용 응답에 실린 본문과 그 형식을 알리는 헤더

위의 두 줄은 한 줄기입니다. 설계에서 정한 엔티티가 표가 됩니다. 그 표의 한 줄을 코드가 객체로 옮겨 다룹니다.

아래 두 줄은 이 줄기와 따로 붙은 이름입니다. 위의 뜻을 알아도 아래 뜻은 짐작이 안 됩니다. 그래서 문서를 읽다 엔티티를 만나면 어느 분야 이야기인지부터 봐야 합니다.

데이터 모델링의 엔티티

데이터 모델링은 담을 데이터를 어떤 덩어리로 나누고 어떻게 이을지 정하는 일입니다. 그렇게 나눈 덩어리 하나하나가 엔티티입니다. 쇼핑몰이라면 고객·주문·상품이 엔티티입니다.

엔티티라는 말은 고객이라는 종류를 가리키기도 합니다. 고객 한 명을 가리키기도 합니다. 두 쓰임을 가르는 법은 아래 「종류와 하나」 소절에서 봅니다.

엔티티가 되려면 하나하나를 따로 알아볼 수 있어야 합니다. 고객은 한 명 한 명이 서로 다른 사람이라 가려서 기록해야 합니다. 주문도 한 건 한 건을 가려야 배송하고 환불할 수 있습니다.

엔티티를 먼저 정하는 까닭은 같은 사실을 한 곳에만 적기 위해서입니다. 고객을 따로 떼어 두지 않으면 주문을 받을 때마다 고객의 이름과 주소를 주문 옆에 되풀이해 적게 됩니다. 그러면 주소가 바뀔 때 그 고객의 주문을 전부 찾아 고쳐야 합니다. 하나라도 놓치면 한 고객의 주소가 두 가지로 남습니다.

엔티티와 속성

고객의 이름이나 주소는 엔티티가 아닙니다. 고객이라는 엔티티에 딸린 값입니다. 엔티티에 딸려 그 엔티티가 어떠한지를 적는 값을 속성이라고 합니다.

무엇이 엔티티이고 무엇이 속성인지는 요구사항이 정합니다. 주소를 글자 한 줄로만 적어 두면 주소는 고객의 속성입니다. 배송지를 여러 개 저장해 두고 주문 때마다 하나를 고르게 하려면 사정이 달라집니다. 그때는 주소를 따로 떼어 배송지라는 엔티티로 둡니다.

종류와 하나

실무에서 엔티티라는 말은 두 층을 함께 가리킵니다. 「고객 엔티티를 설계했다」라고 하면 고객이라는 종류 전체를 말합니다. 「엔티티 하나를 지웠다」라고 하면 고객 한 명을 말합니다.

둘을 나눠 부를 때는 종류 쪽을 엔티티 타입, 그 종류에 속하는 하나를 엔티티 인스턴스라고 합니다. 대화에서는 둘 다 엔티티라고 부르는 일이 많습니다. 앞뒤 말을 보고 어느 층인지 가립니다.

식별자

엔티티 하나를 다른 하나와 가려내려면 기준이 있어야 합니다. 이름은 기준이 되지 못합니다. 같은 이름의 고객이 둘일 수 있기 때문입니다.

그래서 엔티티마다 겹치지 않는 값을 하나 정해 둡니다. 이 값이 식별자입니다. 고객이라면 가입할 때 매기는 고객번호가 식별자입니다.

식별자는 속성이 바뀌어도 변하지 않습니다. 김하나가 이사해 주소가 바뀌어도 고객번호가 같으면 같은 고객입니다. 거꾸로 이름과 주소가 똑같아도 고객번호가 다르면 다른 고객입니다. 속성이 아니라 식별자로 같고 다름을 가린다는 점이 엔티티를 엔티티로 만듭니다.

표로 옮긴 엔티티

설계에서 정한 엔티티는 데이터베이스에 담을 때 표가 됩니다. 엔티티의 각 부분이 표의 어디로 가는지 차례로 봅니다.

관계형 데이터베이스는 데이터를 가로 줄과 세로 칸으로 된 표에 담는 데이터베이스입니다. 이 표를 테이블, 가로 줄 하나를 행, 세로 칸 하나를 열이라고 합니다.

기본 키는 테이블에서 식별자를 담는 열입니다. 행 하나를 콕 집어 가리키는 값입니다. 고객 테이블에서는 고객번호 열이 기본 키입니다.

엔티티끼리의 이어짐이 관계입니다. 주문 한 건이 어느 고객의 것인지가 관계입니다. 이 이어짐은 주문 테이블에 고객번호 열을 두어 남깁니다. 다른 테이블의 기본 키를 적어 두는 이런 열이 외래 키입니다.

지금까지 본 이름을 한데 모으면 아래와 같습니다. 왼쪽이 설계에서 쓰는 이름, 가운데가 테이블에서 쓰는 이름입니다.

설계의 이름 테이블에서 고객의 예
엔티티 타입 테이블 고객 테이블
엔티티 인스턴스 행 김하나의 행
속성 열 이름 열 · 주소 열
식별자 기본 키 고객번호 열
관계 외래 키 주문 테이블의 고객번호 열

엔티티 타입 하나가 테이블 하나가 됩니다. 인스턴스 하나는 행 하나가 됩니다. 그래서 「고객 엔티티를 하나 저장한다」는 말은 고객 테이블에 행을 하나 넣는다는 말과 같습니다.

나눈 만큼 대가도 따릅니다. 주문과 그 주문을 한 고객을 함께 보려면 두 테이블을 이어 붙여 읽어야 합니다. 이렇게 이어 읽는 연산을 조인이라고 합니다. 나눈 방식을 나중에 바꾸려면 쌓인 데이터까지 새 테이블로 옮겨야 합니다.

엔티티와 관계를 선과 상자로 그린 설계도를 ER 다이어그램(Entity-Relationship diagram, 엔티티-관계 다이어그램)이라고 부릅니다. 테이블을 만들기 전에 이 그림으로 엔티티를 먼저 정리하는 일이 많습니다.

코드 속의 엔티티

애플리케이션 코드도 같은 이름을 씁니다. 테이블의 행이 코드의 객체가 되는 모습을 짧은 자바 코드로 봅니다.

코드는 테이블의 행을 행 모양대로 다루지 않고 객체로 바꿔 다룹니다. 행과 객체 사이를 오가며 옮겨 주는 도구를 ORM(Object-Relational Mapping, 객체-관계 매핑)이라고 부릅니다. ORM 을 쓰는 코드에서는 테이블 하나와 짝지은 클래스와 그 클래스의 객체를 엔티티라고 부릅니다.

자바에서 ORM 을 쓰는 표준 방식이 JPA(Java Persistence API)입니다. JPA 에서는 클래스에 @Entity 를 붙여 엔티티임을 밝힙니다. 식별자를 담는 필드에는 @Id 를 붙입니다.

Java
@Entity
public class Customer {
    @Id
    private Long id;         // 고객번호 열
    private String name;     // 이름 열
    private String address;  // 주소 열
}

Customer 클래스가 고객 테이블과 짝을 이룹니다. 필드 하나가 열 하나에 대응합니다. 이 클래스의 객체 하나는 고객 테이블의 행 하나를 담습니다.

코드 속 엔티티도 식별자로 같고 다름을 가립니다. 두 객체의 id 가 같으면 같은 고객을 담은 것으로 봅니다. name 을 고쳐도 id 가 같으면 같은 고객입니다.

설계에서 코드까지 같은 고객이 어떻게 이어지는지 그리면 아래와 같습니다. 엔티티라는 이름은 맨 위 설계와 맨 아래 코드에서 쓰입니다. 가운데 데이터베이스에서는 테이블과 행이라고 부릅니다.

flowchart TD
    subgraph D["설계 · 데이터 모델링"]
        E["고객 엔티티"]
    end
    subgraph B["관계형 데이터베이스"]
        T["고객 테이블"] --> R["김하나의 행"]
    end
    subgraph C["애플리케이션 코드"]
        K["Customer 엔티티 클래스"] --> O["김하나를 담은 객체"]
    end
    E -->|표로 옮긴다| T
    R -->|ORM 이 옮겨 담는다| O

엔티티와 헷갈리는 객체

코드에는 엔티티 말고도 데이터를 담는 객체가 여럿 있습니다. 그중 자주 섞이는 둘을 엔티티와 가릅니다. 가르는 기준은 식별자가 있느냐입니다.

값 객체는 식별자 없이 값만으로 같고 다름을 가리는 객체입니다. 금액 5,000원이나 주소 하나가 그렇습니다. 값이 같으면 어느 쪽을 써도 같은 것으로 봅니다.

DTO(Data Transfer Object, 데이터 전송 객체)는 계층이나 서비스 사이에 데이터를 실어 나르기만 하는 객체입니다. 바깥으로 보낼 응답 모양을 담는 객체가 흔한 예입니다. 식별자를 가질 필요가 없습니다. 테이블과 짝을 이루지도 않습니다.

엔티티를 응답으로 바로 내보내지 않고 DTO 로 옮겨 담는 까닭이 여기 있습니다. 엔티티는 테이블과 짝이라 테이블에 열이 하나 늘면 엔티티에도 필드가 늘어납니다. 엔티티를 응답에 바로 실으면 그 필드도 응답에 함께 나갑니다. DTO 를 사이에 두면 테이블이 바뀌어도 응답 모양은 DTO 가 정한 대로 남습니다.

XML 의 엔티티

여기부터는 줄기가 다른 뜻입니다. XML 문서 안에서 엔티티가 무엇을 하는지 짧은 예 둘로 봅니다.

XML 의 엔티티는 이름을 붙여 둔 글 조각입니다. 문서 안에 &이름; 을 적으면 그 이름이 가리키는 글 조각이 그곳에 들어갑니다. 이렇게 이름을 불러 쓰는 표기를 엔티티 참조라고 합니다.

첫 쓰임은 특수 문자입니다. XML 에서 < 는 태그가 시작한다는 표시입니다. 그래서 본문 글자로 「3 < 5」를 적으려면 < 를 바로 쓸 수 없습니다. 이때 미리 정해진 엔티티 &lt; 를 씁니다.

XML
<expr>3 &lt; 5</expr>  <!-- 3 < 5 -->

XML 문서를 읽어 구조로 풀어내는 프로그램을 파서라고 합니다. 파서는 &lt; 를 읽어 < 로 바꿉니다.

XML 이 미리 정해 둔 엔티티는 아래 다섯입니다.

엔티티 참조 바뀌는 글자
&lt; <
&gt; >
&amp; &
&apos; '
&quot; "

두 번째 쓰임은 되풀이되는 글을 한 곳에 모아 두는 것입니다. 문서 앞머리에는 그 문서가 따를 규칙을 적는 머리말을 둘 수 있습니다. 이 머리말이 문서 타입 선언입니다. 여기서 엔티티를 직접 정의할 수 있습니다.

XML
<!DOCTYPE memo [
  <!ENTITY team "백엔드 팀">
]>
<memo>&team;</memo>  <!-- 백엔드 팀 -->

<!ENTITY> 줄이 team 이라는 이름에 「백엔드 팀」을 묶어 둡니다. 문서에서 &team; 을 적은 곳마다 이 글이 들어갑니다. 팀 이름이 바뀌면 선언 한 줄만 고치면 됩니다.

XML 문서는 이런 글 조각 여럿으로 나눠 담을 수 있습니다. 그래서 XML 에서는 엔티티를 문서를 이루는 저장 단위라고도 합니다. 저장 단위라는 말도 이름을 붙여 둔 글 조각을 가리킵니다.

글 조각의 내용이 꼭 선언 안에 적혀 있어야 하는 것은 아닙니다. 문서 밖의 파일을 가리키게 선언해 그 파일의 내용을 끌어올 수도 있습니다. 이런 엔티티를 외부 엔티티라고 합니다.

외부 엔티티와 XXE

외부 엔티티는 파일 경로나 웹 주소를 내용으로 가리킵니다. 파서는 그 파일을 읽어 엔티티를 참조한 곳에 끼워 넣습니다. 이 기능이 공격 통로가 됩니다.

서버가 바깥에서 받은 XML 을 파싱한다고 해 봅시다. 공격자는 /etc/passwd 처럼 서버 안의 파일을 가리키는 외부 엔티티를 문서에 넣어 보냅니다.

XML
<!DOCTYPE memo [
  <!ENTITY x SYSTEM "file:///etc/passwd">
]>
<memo>&x;</memo>  <!-- 파일 내용 -->

SYSTEM 은 뒤에 오는 주소의 파일을 엔티티의 내용으로 삼는다는 표시입니다. 파서가 그 파일을 읽어 &x; 에 끼워 넣으면 파일 내용이 응답이나 오류 메시지에 실려 밖으로 나갑니다.

이 공격을 XXE(XML External Entity, XML 외부 엔티티) 공격이라고 부릅니다. 막는 방법은 바깥에서 받은 XML 을 파싱할 때 외부 엔티티와 문서 타입 선언을 처리하지 않도록 파서 설정을 끄는 것입니다.

HTML(HyperText Markup Language) 문서에도 같은 표기가 있습니다. &lt; · &amp; 같은 표기를 웹 개발에서는 흔히 「HTML 엔티티」라고 부릅니다.

HTTP 의 엔티티

HTTP 는 요청과 응답에 실려 오가는 내용을 예전에 엔티티라고 불렀습니다. 본문에 Content-Type · Content-Length 처럼 본문의 형식이나 길이를 알리는 헤더를 함께 묶은 말입니다. 지금은 같은 것을 표현(representation)이라고 합니다.

옛 이름의 흔적이 엔티티 태그에 남아 있습니다. 엔티티 태그는 서버가 응답 내용의 판마다 붙이는 짧은 문자열입니다. 헤더 이름을 따서 흔히 ETag 라고 부릅니다. 내용이 바뀌면 이 문자열도 바뀝니다.

어느 뜻인지 가르는 단서

글에서 엔티티를 만나면 함께 나온 낱말을 보면 됩니다. 아래 표는 자주 같이 나오는 낱말과 그때의 뜻입니다.

함께 나오는 말 뜻
속성 · 관계 · 식별자 · ER 다이어그램 데이터 모델링의 엔티티
ORM · JPA · @Entity · 값 객체 · DTO 코드 속의 엔티티
& 로 시작하는 표기 · 문서 타입 선언 · 파서 · XXE XML 의 엔티티
헤더 · 본문 · 엔티티 태그 HTTP 의 엔티티

관련 항목

엔티티와 함께 데이터 모델을 이루는 구성 요소

속성 · 관계 · 식별자 · 카디널리티 · ER 다이어그램 · 개체 관계 모델 · 데이터 모델링 · 개념 모델 · 논리 모델

엔티티를 담는 관계형 데이터베이스의 단위와 키

관계형 데이터베이스 · 테이블 · 행 · 열 · 기본 키 · 외래 키 · 대리 키 · 자연 키

엔티티를 설계할 때 따르는 규칙

정규화 · 비정규화 · 스키마 · 참조 무결성

엔티티를 코드의 객체로 옮기는 도구

ORM · JPA · Hibernate · 액티브 레코드 · 데이터 매퍼 · 영속성 컨텍스트 · 지연 로딩

코드에서 엔티티와 맞세워지는 객체

값 객체 · DTO · 애그리거트 · 도메인 주도 설계 · 도메인 모델

XML 문서 안의 엔티티를 다루는 문법

XML · 문서 타입 선언 · DTD · 엔티티 참조 · 문자 참조 · CDATA · 마크업 · 파서 · HTML

XML 엔티티를 노리는 공격

XXE · 외부 엔티티 · Billion Laughs · SSRF

HTTP 에서 엔티티라는 이름이 남은 용어

HTTP · 엔티티 태그 · ETag · 표현 · 조건부 요청 · 메시지 본문

다른 이름: entity · 엔터티 · 개체