
Spring Data JPA에서 등록 시간(regTime)과 수정 시간(updateTime)을 자동으로 관리하기 위한 공통 엔티티 글래스
이 클래스를 다른 엔티티에서 extends BaseTimeEntity처럼 상속만 하면, 날짜 자동 관리가 편하게 된다.
JPA 엔티티에 변경 사항이 생겼을 때, 시간 정보를 자동으로 기록해주는 리스너를 등록한다. @CreatedDate나 @LastModifiedDate를 처리해준다.
해당 클래스를 직접 테이블로 만들지는 않지만, 상속받는 엔티티가 클래스의 필드를 상속받는 엔티티가 이 클래스의 필드를 그대로 사용할 수 있게 해주는 설정이다.
예 : Item extends BaseTimeEntity → Item 엔티티에 regTime, updateTime 컬럼이 생김
롬복(Lombok) 어노테이션으로, 해당 클래스의 모든 필드에 대한 getter/setter 자동으로 생성한다.
엔티티가 처음 저장될 때 자동으로 현재 시각을 저장
한 번 값이 저장되면 변경되지 않도록 설정한다.
엔티티가 수정될 때마다 자동으로 현재 시간으로 갱신한다.

작성자(createdBy), 수정자(modifiedBy) 정보를 자동으로 관리하는 공통 엔티티 클래스
BaseTimeEntity를 상속해서 시간 정보 + 작성자 정보를 함께 관리하도록 확장했다.

DB 테이블과 연결되는 "회원 정보" 테이블
PK 값을 자동 생성 (AUTO : DB에 밭긴다)
strategy -> 전략
문자열 값으로 DB에 저장한다.

DB 테이블과 연결되는 "아이템 정보" 테이블
Large Object -> 큰 텍스트 저장에 사용(DB에서는 CLOB 또는 TEXT)
CLOB -> Character Large Object, 문자 데이터(텍스트)를 대용량으로 저장할 수 있는 DB 타입
DB 테이블과 연결되는 "장바구니 정보" 테이블

1:1 연관 관계 -> 하나의 장바구니는 하나의 회원과 연결된다.
FetchType.LAZY로 지연 로딩을 의미하며, member 필드는 실제로 접근할 때 쿼리가 실행된다. (필요한 경우에만 조회)
Cart 테이블에서 외래 키(FK) 컬럼 이름을 member_id로 지정한다.
이 컬럼을 통해 Member 테이블의 PK를 참조한다.

DB 테이블과 연결되는 "장바구니 안의 상품과 수량 정보" 테이블
전략이 생략된 경우 기본 전략 사용 -> AUTO
하나의 Cart에는 여러 개의 CartItem이 있을 수 있다.
하나의 Item은 여러 장바구니 항목에 들어갈 수 있다.

@OneToMany : 하나의 주문에 여러 상품이 포함되어 를 사용한다. mappedBy = "order" : OrderItem 클래스의 order 필드에 의해 매핑된다.cascade = CascadeType.ALL : 주문 저장/삭제 시 주문 항목(orderItem)도 함께 저장/삭제orphanRemoval = true : orderItems 리스트에서 항목을 제거하면 DB에서도 삭제된다. 자바는 클래스 간 다중 상속을 지원하지 않는다. 자바에서 공통으로 쓰고 싶은 코드가 많아도 다른 클래스를 여러 개 상속할 수는 없다. 하지만 BaseTimeEntity는 일반 클래스가 아니라 추상클래스이고 '기본 정보만 담은 부모 클래스'를 상속하는 방식은 JPA에서 자주 사용하는 패턴이다.
자바에서 다중 상속에 관해 찾아보니
컴포지션(composition)을 사용하는 방법도 있었다. 컴포지션은 다른 클래스를 내부 필드(멤버 변수)로 포함시켜서 기능을 사용하는 것이다. 어떤 기능이 필요하면 그걸 가진 객체를 안에 넣어쓰는 방식이다.
// 상속만 사용하는 경우
// Order가 이미 다른 클래스를 상속하고 있다면 Logger를 상속 받을 수 없다.
class Logger {
void log(String msg) {
System.out.println("Log: " + msg);
}
}
class Order extends Logger { // Logger 상속
void placeOrder() {
log("주문 생성됨");
}
}
// 컴포지션
class Logger {
void log(String msg) {
System.out.println("Log: " + msg);
}
}
class Order {
private Logger logger = new Logger(); // 포함시킴
void placeOrder() {
logger.log("주문 생성됨"); // 위임해서 사용
}
}
외래 키(FK)를 갖고 있는 쪽에서
@ManyToOne을 사용한다.
| 항목 | cascade = CascadeType.ALL | orphanRemoval = true |
|---|---|---|
| 목적 | 부모 엔티티 저장/삭제 시 자식도 자동 처리 | 부모-자식 관계가 끊어지면 자식 삭제 |
| 트리거 조건 | 부모를 persist, remove 등 할 때 | 컬렉션(List 등)에서 자식이 제거될 때 |
| DB 영향 | 자식 insert/delete 발생 | 자식 delete 발생 |
| 주요 기능 | 저장, 삭제, 병합 등 전파 | "고아 객체" 자동 삭제 |
| 기본 사용 예 | order.save() 시 orderItem도 같이 저장 | orderItem을 리스트에서 remove()하면 삭제됨 |
cascade = ALL
→ "부모 따라 자식도 같이 저장하고 같이 지움"
→ orderRepository.save(order) 하면 orderItems도 자동 저장됨
orphanRemoval = true
→ "자식이 부모랑 연결이 끊기면 DB에서도 삭제"
→ order.getOrderItems().remove(item) 하면 item이 DB에서도 삭제됨