객체와 테이블 매핑 : @Entity @Table
필드와 컬럼 매핑 : @Column
기본 키 매핑 : @Id
연관관계 매핑 : @ManyToOne @JoinColumn
@Entity주의
속성: name
• JPA에서 사용할 엔티티 이름을 지정한다.
• 기본값: 클래스 이름을 그대로 사용(예: Member)
• 같은 클래스 이름이 없으면 가급적 기본값을 사용한다.
@Table은 엔티티와 매핑할 테이블 지정

DDL을 애플리케이션 실행 시점에 자동 생성
• 테이블 중심 -> 객체 중심
• 데이터베이스 방언을 활용해서 데이터베이스에 맞는 적절한DDL 생성
• 이렇게 생성된 DDL은 개발 장비에서만 사용
• 생성된 DDL은 운영서버에서는 사용하지 않거나, 적절히 다듬은 후 사용

운영 장비에는 절대 create, create-drop, update 사용하면
안된다.
• 개발 초기 단계는 create 또는 update
• 테스트 서버는 update 또는 validate
• 스테이징과 운영 서버는 validate 또는 none
제약조건 추가: 회원 이름은 필수, 10자 초과X
• @Column(nullable = false, length = 10)
@Table(uniqueConstraints = {@UniqueConstraint( name = "NAME_AGE_UNIQUE",
columnNames = {"NAME", "AGE"} )})
• DDL 생성 기능은 DDL을 자동 생성할 때만 사용되고
JPA의 실행 로직에는 영향을 주지 않는다.


자바 enum 타입을 매핑할 때 사용
주의! ORDINAL 사용X

🚨 문제 발생 가능성
CANCELED를 중간에 추가하면 기존 데이터와 충돌 가능public enum OrderStatus {
PENDING, // 0
SHIPPED, // 1
CANCELED, // 2 (새로 추가)
DELIVERED // 3 (기존 2 → 3으로 변경됨!)
}
❌ 기존에 DELIVERED(2)로 저장된 데이터가 CANCELED(2)로 잘못 해석될 수 있음!
→ 데이터 무결성 문제 발생
@Enumerated(EnumType.STRING)
private OrderStatus status;
✔ status 값이 SHIPPED일 때, DB에는 "SHIPPED" (문자열)로 저장
✔ enum 값이 변경되어도 기존 데이터 영향 없음
sql
복사편집
SELECT * FROM order;
+----+-----------+
| id | status |
+----+-----------+
| 1 | PENDING |
| 2 | SHIPPED |
| 3 | DELIVERED |
+----+-----------+
날짜 타입(java.util.Date, java.util.Calendar)을 매핑할 때 사용
참고: LocalDate, LocalDateTime을 사용할 때는 생략 가능(최신 하이버네이트 지원)

데이터베이스 BLOB, CLOB 타입과 매핑
• @Lob에는 지정할 수 있는 속성이 없다.
• 매핑하는 필드 타입이 문자면 CLOB 매핑, 나머지는 BLOB 매핑
• CLOB: String, char[], java.sql.CLOB
• BLOB: byte[], java.sql. BLOB
필드 매핑X
데이터베이스에 저장X, 조회X
주로 메모리상에서만 임시로 어떤 값을 보관하고 싶을 때 사용
Identity : DB에 위임, mysqlSeqience : DB 시퀀스 오브젝트 사용, orcleTable : 키 생성용 테이블 사용, 모든 DB에서 사용Auto : 방언에 따라 자동 지정, 기본값기본 키 제약 조건 : null아님, 유일, 변하면 안되낟.
미래까지 이 조건을 만족하는 자연키는 찾기 어렵다. 대리키(대체키)를 사용하자
예를 들어 주민등록번호도 기본 키로 적잘하지 않다.
권장 : Long형 + 대체키 + 키 생성전략 사용
의미 없는 숫자 값으로 만든, 순수하게 식별만을 위한 키
예:
id: 1, id: 2, id: 3 이런 식
보통 Long 타입, AUTO_INCREMENT or SEQUENCE로 자동 생성
👉 장점:
예시
@Entity
public class Member {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY) // 또는 SEQUENCE
private Long id; // ✅ 대체키 (무의미한 숫자)
private String name;
@Column(unique = true)
private String ssn; // 주민번호 등은 유니크 제약만 걸자
}
그냥 쓰다보니까 ManyTOMany를 쓰지말라고해서 안썼고 중간테이블을 외우는 식으로 썼던거같다.
✅ 다대다 관계가 뭔데?
예를 들어:
하나의 주문은 여러 상품을 담을 수 있음
하나의 상품은 여러 주문에 포함될 수 있음
즉,
ORDER ⬄ ITEM
N N
다대다 매핑을 하면
❌ 다대다를 직접 매핑하면 이런 문제가 생겨:
@ManyToMany
@JoinTable(name = "order_item",
joinColumns = @JoinColumn(name = "order_id"),
inverseJoinColumns = @JoinColumn(name = "item_id"))
private List<Item> items;
이렇게 하면:
✅ 그래서 중간에 "주문상품" (OrderItem) 엔티티를 둬서 푸는 거야
ORDER → ORDER_ITEM ← ITEM
1 ⬄ N N ⬄ 1
즉, 다대다를 두 개의 일대다, 다대일 관계로 쪼개는 것
🔥 한쪽 테이블에 넣으면 생기는 문제들
@Entity
public class Item {
...
private int count; // ❌ 주문마다 달라지는 값을 상품에 넣는다?
}
상품은 하나의 정보야 (예: "아이폰 1TB")
근데 count는 주문마다 달라지는 값이야
여러 주문이 하나의 상품을 쓰는데, count를 상품에 넣으면 누가 얼마나 샀는지 섞여버림
→ 주문 1에서는 2개 샀고, 주문 2에서는 5개 샀는데, Item.count는 몇일까? 🤯
private List<Integer> countList;
이건 데이터 정합성 완전 박살남
items.get(0)에 해당하는 상품이 countList.get(0)이겠지? → 인덱스 맞추기 오류나기 딱 좋음
→ 유지보수 지옥 열림
class Order {
private List<Item> items; // 주문한 상품들
private List<Integer> countList; // 각 상품별 수량
private List<Integer> discountList; // 각 상품별 할인율
}
items.add(itemA); // index 0
countList.add(2); // index 0
discountList.add(10); // index 0
items.remove(0); // 상품만 삭제
// countList, discountList는 그대로… ❌
→ 상품과 수량/할인이 일치하지 않음
→ 정합성 붕괴: 누가 몇 개 샀는지, 얼마에 샀는지 영원히 모르게 됨
items, countList, discountList 전부 개별 리스트
항상 "같은 인덱스"를 공유한다고 믿고 있어야 해 → 사고 나기 딱 좋음
리스트 하나만 수정하면 다른 리스트는 망가짐
class OrderItem {
private Item item;
private int count;
private int discountRate;
}
class Order {
private List<OrderItem> orderItems;
}
→ 이제 OrderItem 객체 하나가 상품 + 수량 + 할인을 한 덩어리로 묶어줌
→ 수정/삭제/조작 다 안전하게 할 수 있어
→ 인덱스 걱정도 없음, orderItem.getItem(), getCount()으로 접근
✅ 한줄 요약
List + List 방식은 관계형 데이터 세계에서 가장 위험한 조합 중 하나야.
항상 관련 데이터는 객체로 묶어서 같이 움직이게 만들어야 해!