Home > Backend Development > 📚[Backend Development] 🚀 @Entity

📚[Backend Development] 🚀 @Entity
Backend Development Server Java Lombok

🎯 JPA @Entity 완벽 가이드

JPA의 시작점이자 핵심! @Entity를 정확하게 이해하고 실무에 바로 적용해보세요.


📋 목차

  1. @Entity가 뭔가요?
  2. @Entity의 핵심 역할
  3. 언제 사용해야 할까?
  4. 반드시 지켜야 할 4가지 규칙
  5. 절대 사용하면 안 되는 경우
  6. Entity vs DTO vs VO 비교
  7. 실무 표준 템플릿
  8. 핵심 요약

1️⃣ @Entity가 뭔가요?

@Entity는 JPA에서 클래스에게 특별한 신분을 부여하는 어노테이션입니다.

@Entity
public class Member {
    // 이 클래스는 이제 특별합니다! 🌟
}

🎭 이 한 줄의 의미

“이 클래스의 인스턴스는 데이터베이스 테이블의 한 행(row)과 1:1로 매핑된다”

🔄 객체와 DB의 관계

자바 세계 🖥️ 데이터베이스 세계 💾
클래스 (Class) 테이블 (Table)
객체 (Object) 행 (Row)
필드 (Field) 컬럼 (Column)

실제 변환 예시

// Java 코드
@Entity
public class Member {
    private Long id;
    private String name;
}

⬇️ JPA가 자동으로 변환 ⬇️

-- Database Table
CREATE TABLE member (
    id BIGINT,
    name VARCHAR(255)
);

2️⃣ @Entity의 핵심 역할

@Entity가 붙으면 JPA에게 다음과 같은 슈퍼파워를 위임합니다:

기능 설명
🗂️ 테이블 매핑 클래스를 DB 테이블과 연결
🔍 조회 (SELECT) 데이터 읽기
💾 저장 (INSERT) 데이터 생성
✏️ 수정 (UPDATE) 데이터 변경
🗑️ 삭제 (DELETE) 데이터 제거
🎪 영속성 관리 객체 생명주기 추적

💡 핵심: JPA가 당신의 객체 생명주기를 완전히 관리합니다!


3️⃣ 언제 사용해야 할까?

✅ Case 1: DB에 저장해야 하는 도메인 객체

@Entity
public class Order {
    @Id
    private Long id;
    private String productName;
    private int quantity;
}

적용 대상:

  • 👤 회원 (Member)
  • 📦 주문 (Order)
  • 🛍️ 상품 (Product)
  • 📝 게시글 (Post)

판단 기준: “이 데이터가 DB에 영구적으로 저장되어야 하나?” → YES면 @Entity


✅ Case 2: JPA Repository로 관리하고 싶을 때

public interface MemberRepository extends JpaRepository<Member, Long> {
    // Member는 반드시 @Entity여야 합니다!
}

✅ Case 3: 변경 감지가 필요할 때 (Dirty Checking)

// 트랜잭션 안에서
Member member = memberRepository.findById(1L).orElseThrow();
member.changeName("Kobe");  // 이름만 변경

// save() 호출 없이도 자동으로 UPDATE 쿼리 발생! 🎉

Entity만의 특권: 변경 감지 자동화


4️⃣ 반드시 지켜야 할 4가지 규칙

🔹 규칙 1: 기본 생성자 필수

@Entity
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class Member {
    // JPA가 리플렉션으로 객체를 생성하기 위해 필요
}
접근 제어자 사용 가능? 추천
private -
protected ⭐⭐⭐
public

💡 실무 표준: protected 사용 (무분별한 객체 생성 방지)


🔹 규칙 2: @Id 필수

@Entity
public class Member {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;  // 기본 키 없으면 Entity가 아님!
}

🔹 규칙 3: final 클래스 금지

public final class Member { }  // ❌ 프록시 생성 불가!

이유: JPA는 지연 로딩을 위해 프록시 객체를 생성하는데, final 클래스는 상속 불가


🔹 규칙 4: 필드 접근 방식 일관성

@Entity
public class Member {
    @Id  // 필드에 @Id → 모든 필드 접근
    private Long id;

    private String name;  // getter 없어도 OK
}
@Entity
public class Member {
    private Long id;

    @Id  // getter에 @Id → 모든 getter 접근
    public Long getId() {
        return id;
    }
}

⚠️ 주의: 필드 접근과 getter 접근을 섞지 마세요!


5️⃣ 절대 사용하면 안 되는 경우

❌ Case 1: DTO (Data Transfer Object)

// ❌ 잘못된 사용
@Entity
public class MemberRequest {
    private String name;
    private String email;
}
// ✅ 올바른 사용
public class MemberRequest {
    private String name;
    private String email;
}

이유:

  • DB 저장 대상 아님
  • 단순 데이터 전달용
  • 상태 관리 불필요

❌ Case 2: VO (Value Object)

// ❌ 잘못된 사용
@Entity
public class Money {
    private int value;
}
// ✅ 올바른 사용
@Embeddable  // or 일반 클래스
public class Money {
    private final int value;  // 불변
}

❌ Case 3: 유틸리티/계산 클래스

// ❌ @Entity 불필요
public class PriceCalculator {
    public int calculate(int price, int discount) {
        return price - discount;
    }
}

6️⃣ Entity vs DTO vs VO 비교

특성 Entity 🏛️ DTO 📮 VO 💎
DB 매핑
상태 변경 ❌ (불변)
식별자 (@Id)
JPA 관리
목적 도메인 모델 데이터 전달 값 표현
생명주기 영속성 컨텍스트 요청/응답 범위 사용 시점

🎯 언제 무엇을 사용할까?

클라이언트 → [DTO] → Controller → Service → [Entity] ↔ Repository ↔ DB
                                      ↓
                                   [VO] (도메인 내부 값)

7️⃣ 실무 표준 템플릿

🌟 완벽한 Entity 클래스 예제

@Entity
@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class Member {

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

    @Column(nullable = false, length = 50)
    private String name;

    @Column(unique = true, nullable = false)
    private String email;

    @Enumerated(EnumType.STRING)
    private MemberStatus status;

    private LocalDateTime createdAt;

    // 정적 팩토리 메서드 (권장)
    public static Member create(String name, String email) {
        Member member = new Member();
        member.name = name;
        member.email = email;
        member.status = MemberStatus.ACTIVE;
        member.createdAt = LocalDateTime.now();
        return member;
    }

    // 도메인 로직
    public void changeName(String name) {
        if (name == null || name.isBlank()) {
            throw new IllegalArgumentException("이름은 필수입니다.");
        }
        this.name = name;
    }

    public void deactivate() {
        this.status = MemberStatus.INACTIVE;
    }
}

✨ 이 템플릿의 장점

요소 장점
@NoArgsConstructor(PROTECTED) 무분별한 생성 방지
@Getter 불필요한 Setter 제거
정적 팩토리 메서드 명확한 생성 의도
도메인 로직 메서드 비즈니스 로직 캡슐화
@Column 옵션 DB 제약조건 명시

8️⃣ 핵심 요약

💡 한 문장 정리

@Entity는 “이 클래스는 DB에 저장되고, JPA가 생명주기를 관리한다”는 선언이다.

📌 기억해야 할 공식

✅ DB 테이블과 1:1 매핑 = @Entity
✅ 조회/저장/수정 대상 = @Entity
❌ 단순 전달용 객체 = @Entity 붙이지 마세요!

🎓 실무 체크리스트

  • 기본 생성자 있나요? (protected 권장)
  • @Id 필드 있나요?
  • final 클래스 아니죠?
  • DTO/VO와 혼동하지 않았나요?
  • 도메인 로직이 Entity에 있나요?

🚀 다음 학습 주제

  • @Table, @Column 상세 옵션
  • 연관관계 매핑 (@OneToMany, @ManyToOne)
  • 영속성 컨텍스트와 1차 캐시
  • 변경 감지 (Dirty Checking) 원리