Notice
Recent Posts
Recent Comments
Link
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | |||
5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 | 27 | 28 | 29 | 30 | 31 |
Tags
- 자바의 정석 기초편 ch11
- 자바의 정석 기초편 ch12
- 자바의 정석 기초편 ch13
- 스프링 mvc1 - 서블릿
- 스프링 고급 - 스프링 aop
- 자바의 정석 기초편 ch3
- @Aspect
- 자바의 정석 기초편 ch14
- 타임리프 - 기본기능
- 게시글 목록 api
- 자바의 정석 기초편 ch9
- 자바의 정석 기초편 ch4
- 자바의 정석 기초편 ch7
- 자바의 정석 기초편 ch1
- 2024 정보처리기사 수제비 실기
- 스프링 db2 - 데이터 접근 기술
- 스프링 mvc2 - 타임리프
- 2024 정보처리기사 시나공 필기
- jpa 활용2 - api 개발 고급
- 자바의 정석 기초편 ch6
- 스프링 입문(무료)
- 스프링 mvc1 - 스프링 mvc
- 스프링 mvc2 - 검증
- 스프링 db1 - 스프링과 문제 해결
- 자바의 정석 기초편 ch8
- 자바의 정석 기초편 ch5
- 코드로 시작하는 자바 첫걸음
- 자바의 정석 기초편 ch2
- jpa - 객체지향 쿼리 언어
- 스프링 mvc2 - 로그인 처리
Archives
- Today
- Total
나구리의 개발공부기록
엔터티 매핑, 객체와 테이블 매핑, 데이터베이스 스키마 자동 생성, 필드와 컬럼 매핑, 기본 키 매핑, 실전 예제1 - 요구사항 분석과 기본 매핑 본문
인프런 - 스프링부트와 JPA실무 로드맵/자바 ORM 표준 JPA 프로그래밍 - 기본편
엔터티 매핑, 객체와 테이블 매핑, 데이터베이스 스키마 자동 생성, 필드와 컬럼 매핑, 기본 키 매핑, 실전 예제1 - 요구사항 분석과 기본 매핑
소소한나구리 2024. 10. 7. 11:34출처 : 인프런 - 자바 ORM 표준 JPA 프로그래밍 - 기본편(유료) / 김영한님
유료 강의이므로 정리에 초점을 두고 코드는 일부만 인용
Entity 매핑 소개
- 객체와 테이블 매핑 : @Entity, @Table
- 필드와 컬럼 매핑: @Column
- 기본 키 매핑: @Id
- 연관관계 매핑: @ManyToOne, @JoinColumn
1. 객체와 테이블 매핑
1) @Entity
- @Entity 애노테이션이 붙은 클래스는 JPA가 관리하며 엔터티라고 부르고 JPA를 사용해서 테이블과 매핑할 클래스는 @Entity가 필수임
- JPA 스펙상 기본 생성자가 필수임(파라미터가 없는 public or protected 생성자)
- final 클래스, enum, interface, inner 클래스에는 사용 불가
- 저장할 필드에 final 사용 불가
(1) 속성 name
@Entity(name = "Member")
public class Member {
}
- JPA에서 사용할 엔터티 이름을 지정하며 기본값은 현재 클래스 이름을 그대로 사용함
- JPA가 내부적으로 구분하기 위한 이름이며 만약 같은 패키지에 동일한 클래스의 이름이 있고, 둘다 JPA를 사용해야한다면 이런식으로 name으로 바꿔 주어야 함
- 그러나 ... 클래스이름을 다르게 설정하면 되므로 보통 기본값을 사용함
2) @Table
- 실제 매핑할 DB의 테이블을 지정하며 기본값은 엔터티의 이름을 사용함
- 클래스의 이름은 Member인데 특정 사유로 다른 테이블에 매핑을 해야할 때 사용하며, 데이터베이스마다 지원하는 catalog나 schema도 매핑할 수 있고, uniqueConstraints(DDL 생성 시 유니크 제약조건 생성)도 할 수 있음
@Entity
@Table(name = "TTT") // 클래스 이름은 Member지만 TTT 테이블과 매핑됨
public class Member{
}
- 만약 하이버네이트의 hbm2ddl.auto 설정이 create로 되어있으면 TTT라는 새로운 테이블을 생성함
2. 데이터베이스 스키마 자동 생성
<property name="hibernate.hbm2ddl.auto" value="create" />
- JPA에서는 DDL을 애플리케이션 실행 시점에 자동으로 생성하여 개발 단계에서 테이블을 미리 생성하는 등의 번거로운 작업없이 개발할 수 있는 기능을 지원함
- 적용한 데이터베이스 방언을 활용해서 데이터베이스에 맞는 적절한 DDL을 생성함
- 운영서버에서 잘못 사용하면 데이터가 날라가게 되므로 개발 단계에서만 적용해야 함
1) 속성
- value = "create" : 기본테이블을 삭제 후 다시 생성(DROP + CREATE), 애플리케이션 실행 시 DROP후 매핑 테이블을 생성
- value = "create-drop" : create와 같으나 종료시점에 테이블을 DROP, 테스트 케이스를 실행하여 검증이 된 후 테이블을 깔끔하게 날려야할 때 사용
- value = "update" : 변경된 내용만 반영, 운영 DB에는 사용하면 안됨
- value = "validate" : 엔터티와 테이블이 정상 매핑되었는지만 확인할때 사용
- value = "none" : none이라는 기능은 없고 아무렇게나 써도 해당되는 기능이 없기 때문에 동작하지 않지만 관례상 none이라고 작성함
2) 주의점 - 운영 장비에는 절대 create, create-drop, update를 사용하면 안됨
- 개발 초기 단계는 create or update로 사용
- 테스트 서버는 update or validate를 사용하나 update도 안쓰는 것이 좋음
- 스테이징과 운영 서버는 validate or none으로 사용
- 직접 개발하는 로컬 PC에서만 자유롭게 사용하고 여러명이 쓰는 개발서버(테스트 서버)나 스테이징, 운영 서버 등에는 가급적 사용하지 않는 것을 권장함
- 만약 데이터가 몇 천만건이 있는 상태에서 alter를 잘못 치면 시스템이 중단 될수도 있는데 애플리케이션 로딩 시점에 시스템이 자동으로 alter를 날린다는 것은 상당히 큰 리스크가 있음
- 운영 서버에 스크립트를 반영하려면 가급적 적용할 스크립트를 직접 짜서 테스트에서 반영을 해보고 적용해야 함
- 다만, 해당 옵션을 사용하면 쿼리를 만들어 주기때문에 로컬에서 적용하여 생성되는 스크립트를 보고 다듬어서 테스트 서버나 운영서버에 넘기는 식으로 하면 처음부터 적용해야 하는 스크립트를 짜는 수고로움을 줄일 수 있음
- 근본적으로 실수로 해당 옵션이 적용되었어도 반영을 못하도록 운영 서버에 alter나 drop을 못하도록 계정 자체를 분리하는 것이 중요함
3) DDL 생성 기능
- @Column의 제약조건, @Table의 유니크 제약조건을 추가할 수 있음
- DDL 생성 기능은 DDL을 자동 생성할때만 사용되고 JPA의 실행 로직에는 영향을 주지 않음 즉, 데이터베이스 스키마에는 영향을 미치지만 JPA 런타임 동작에는 영향을 주지 않아 웹 애플리케이션 성능에 영향이 없이 제약조건을 수정할 수 있음
- NAME과 AGE 컬럼에 중복값이 없도록 @Table에 유니크 제약조건을 설정
- name필드를 null을 허용하지 않고 길이를 10으로 컬럼에 대한 제약조건을 설정
@Entity
@Table(uniqueConstraints = {@UniqueConstraint(name = "NAME_AGE_UNIQUE",
columnNames = {"NAME", "AGE"})})
public class Member {
@Id
private Long id;
@Column(nullable = false, length = 10)
private String name;
private int age;
3. 필드와 컬럼 매핑
1) 요구사항
- 회원을 일반 회원과 관리자로 구분
- 회원 가입일과 수정일이 있어야 함
- 회원을 설명할 수 있는 필드가 있어야하고 이 필드는 길이 제한이 없음
2) 코드 작성
(1) Member
- @Column : 컬럼 매핑, name으로 필드명과 컬럼명을 다르게 설정할 수 있음
- @Temporal : 날짜 타입 매핑
- @Enumerated : enum 타입 매핑
- @Lob : BLOB, CLOB 매핑
- @Transient: 틀정 필드를 컬럼에 매핑하지 않음(매핑 무시)
package hellojpa;
import jakarta.persistence.*;
import java.util.Date;
@Entity
public class Member {
@Id
private Long id;
@Column(name = "name")
private String username;
private Integer age;
@Enumerated(EnumType.STRING)
private RoleType roleType;
@Temporal(TemporalType.TIMESTAMP)
private Date createDate;
@Temporal(TemporalType.TIMESTAMP)
private Date lastModifiedDate;
@Lob
private String description;
public Long getId() {
return id;
}
// Getter, Setter ...
}
(2) RoleType - Enum
package hellojpa;
public enum RoleType {
USER, ADMIN
}
3) 속성 설명
(1) @Column
- name
- 필드와 매핑할 테이블의 컬럼 이름, 기본값은 객체의 필드 이름
- insertable, updateable
- 컬럼을 등록하거나 변경했을 때 반영할 것인지 여부 설정, 기본값은 TRUE이며 FALSE로 설정하더라도 DB에서 강제로 반영할 수 있음
- 가끔 사용
- nullable(DDL)
- null 값의 허용 여부를 설정, false로 설정하면 DDL 생성 시 not null 제약 조건이 붙음
- 자주 사용
- unique(DDL)
- @Table의 uniqueConstraints와 같지만 한 컬럼에 간단히 유니크 제약조건을 걸 때 사용
- 잘 안쓰는 이유는 제약 조건의 이름이 무작위로 알아볼 수 없게 생성되므로 운영서버에서 사용할 수 없어서 @Table의 uniqueConstraints를 사용함
- columnDefinition(DDL)
- 기본값이 아닌 데이터베이스 컬럼 속성을 직접 설정할 수 있음,
- length(DDL)
- 문자 길이 제약조건으로 String 타입에만 사용함, 기본값으로 255의 길이가 적용됨
- precision, scale (DDL)
- BigDecimal, BigInteger 타입에서 사용함
- precision은 소수점을 포함한 전체 자리수를 지정할 수 있고 scale은 소수점의 자리수를 지정할 수 있음
- double, float 타입에는 적용되지 않으며 아주 큰 숫자나 정밀한 소수를 다루어야할 때만 사용함
- 기본값은 precision=19, scale=2
(2) @Enumerated
- 자바의 enum 타입을 매핑할 때 사용함
- 기본값이 enumType.ORDINAL인데 사용하면 안되므로 EnumType.STRING으로 무조건 사용해야 함
- ORDINAL은 enum의 순서정보가 데이터베이스에 저장하고 STRING은 enum의 이름을 데이터베이스에 저장하는데, 순서를 저장하게 되면 enum이 수정되어 순서정보가 바뀌면 데이터베이스의 무결성이 깨져 해결할 수 없은 버그가 발생함
(3) @Temporal
- 날짜 타입을 매핑할 때 사용하며 최신 하이버네이트를 사용할 경우 생략 가능
- 레거시 프로젝트에서는 사용할 일이 있을 수 있으나 최신 하이버네이트네이트에서는 타입을 LocalDate, LocalDateTime을 사용하면 알아서 매핑해주므로 @Temporal 애노테이션을 생략할 수 있음
- TemporalType.DATE : 날짜(년-월-일), 데이터베이스 date 타입과 매핑
- TemporalType.TIME : 시간(시:분:초), 데이터베이스 time 타입과 매핑
- TemporalType.TIMESTAMP : 날짜와 시간(년-월-일 시:분:초), 데이터베이스의 timestamp 타입과 매핑
- 최신 버전의 하이버네이트에서는 private LocalDate localdate, private LocalDateTime localDateTime 처럼 필드를 선언해주면 자동으로 적용됨
(4) @Lob
- 데이터베이스 BLOB, CLOB 타입과 매핑되며 주요 특징은 기링 제한이 없어 대용량 데이터를 저장할 수 있음
- 지정할 수 있는 속성이 없으면 매핑하는 필드 타입이 문자면 CLOB, 나머지는 BLOB으로 매핑 됨
- 긴 텍스트 데이터나 이미지, 동영상 등의 바이너리 데이터에서 사용함
(5) @Transient
- 데이터베이스와 필드를 매핑을 하지 않고 메모리상에서만 사용
- 데이터베이스에 저장되지 않으므로 조회가 당연히 안되며 주로 메모리에서 임시로 어떤 값을 보관하거나 계산을 해야할 때 사용할 수 있지만 일반적으로 자주 사용되지는 않음
4. 기본 키 매핑
1) 기본 키 매핑 방법
@Id @GeneratedValue
private Long id;
(1) @Id
- 엔터티의 기본키(Primary Key)를 설정
- @Id만 사용할 경우 테이블에 값을 입력할 때 자동 생성되지 않고 직접 값을 입력해야함
- 기본키의 타입은 Long을 사용하는 것을 권장함 - Integer를 사용해도 되지만 Long을 사용한다고해서 애플리케이션의 성능이 저하되는게 크지도 않고 생각보다 한도가 금방 차게되어 타입 변경하는 리소스가 더 많이 들게 됨
(2) @GeneratedValud(strategy = GenerationType.전략)
- 기본키의 값을 직접 입력하지 않아도 자동으로 할당해줌
- GenerationType.IDENTITY : 데이터 베이스에 위임 - MYSQL
- GenerationType.SEQUENCE: 데이터베이스 시퀀스 오브젝트를 사용, @SequenceGenerator 필요 - ORACLE
- GenerationType.TABLE: 키 생성용 테이블 사용, @TableGenerator 필요 - 모든 DB에서 사용가능
- GenerationType.AUTO : 방언에 따라 자동으로 지정, 버전에 따라 지정되는 방식이 바뀔 수 있으므로 확인해보고 사용하는 것을 권장 함 - 기본값
1) IDENTITY 전략
@Id @GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
- 기본 키 생성을 데이터베이스에 위임하며 MySQL의 AUTO_INCREMENT처럼 동작함
- MySQL, PostgreSQL, SQL Server, DB2, H2DB에서 사용
- 엔터티가 영속 상태가 되려면 식별자가 필요한데 이 전략은 데이터베이스에 INSERT SQL을 실행한 후에야 식별자를 알 수 있으므로 이 전략은 트랜잭션을 지원하는 쓰기 지연이 동작하지 않고 즉시 INSERT SQL이 실행되는 특징이 있음(JPA 영속성 컨텍스트에서 계속 관리되게 하기 위한 설계)
- 단순한 구조의 애플리케이션에서 많이 사용됨
2) SEQUENCE 전략
@Entity
@SequenceGenerator(name = "member_seq_generator",
sequenceName = "member_seq",
initialValue = 1, allocationSize = 1)
public class Member {
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE,
generator = "member_seq_generator")
private Long id;
// ...
}
- 유일한 값을 순서대로 생성하는 특별한 데이터베이스 오브젝트(오라클의 SEQUENCE)를 사용해 기본 키 값을 생성
- 엔터티를 저장하기 전에 데이터베이스 시퀀스를 사용해 식별자를 조회하고 조회한 식별자를 엔터티에 할당한 후 엔터티를 저장하기 때문에 IDENTITY 전략에 비해 추가적인 SQL이 실행 되므로 DB 통신도 한번 더 발생함
- 순서 정보를 테이블마다 다르게 사용하고 싶거나, 여러 테이블에서 동일한 시퀀스를 공유할 때 사용
- 오라클, PostgreSQL, DB2, H2DB에서 사용가능하며 MySQL8.0 이상 버전에서도 SEQUENCE를 지원하기 시작 했음
(1) @SequenceGenerator 속성 설명
- name : 식별자 생성기의 이름 필수로 적용해야함
- sequenceName : 데이터베이스에 등록되어 있는 시퀀스 이름, 기본값은 hibernate_sequence
- initialValue : DDL 생성시에만 사용되며 시퀀스 DDL을 생성할 때 처음 시작하는 초기 번호를 설정, 기본값은 1
- allocationSize : 시퀀스 한 번 호출에 시퀀스 값이 증가하는 수, 성능 최적화에 사용되며 데이터 베이스 시퀀스 값이 하나씩 증가하도록 설정 되어 있으면 이 값을 반드시 1로 설정해야함, 기본값은 50
- catalog, schema : 데이터베이스 catalog와 schema의 이름 설정
(2) @GenertatedValud 속성 설명
- generator : 생성기의 이름을 지정하며 @SequenceGenerator의 name 속성과 매핑됨
** 참고
- 시퀀스는 트랜잭션 commit 시점과 무관하게 즉시 증가하여 rollback을 해도 이미 증가한 시퀀스의 값을 돌아가지 않음
3) Table 전략
- 키 생성 전용 테이블을 하나 만들어서 데이터 베이스 시퀀스를 흉내내는 전략
- 모든 데이터베이스에 적용 가능하다는 장점이 있으나 성능면에서 각 데이터베이스에서 지원하는 기능을 사용하는 것이 더 좋으므로 거의 사용하지 않음
@Entity
@TableGenerator(name = "member_seq_generator",
table = "my_sequences",
pkColumnValue = "member_seq",
allocationSize = 1)
public class Member {
@Id
@GeneratedValue(strategy = GenerationType.TABLE, generator = "member_seq_generator")
private Long id;
// ...
}
(1) @TableGenerator 속성
- name : 식별자 생성기 이름, 필수 적용
- table : 키를 생성할 테이블명(시퀀스 역할 테이블의 이름), 기본값은 hibernate_sequences
- pkColumnName : 시퀀스 컬럼명, 기본값은 sequence_name
- valueColumnNa : 시퀀스 값 컬럼명, 기본값은 next_val
- pkColumnValue : 키로 사용할 값 이름, 기본값은 엔티티 이름을 적용
- initailValue, allocationSize, catalog, schema, uniqueConstraints는 @Table과 @SequenceGenerator의 속성과 동일한 로직으로 동작하므로 해당 설명을 참조
4) 권장하는 식별자 전략
- 기본 키 제약 조건은 null이 아니고 유일해야하고 변하면 안됨
- 정말 먼 미래까지 해당 조건을 만족하는 자연키(전화번호, userId, 주민등록번호 등) 를 찾기가 어렵기 때문에 대리키(대체키)를 사용
- Long타입 + 대체키(UUID, Sequence 등) + 키 생성 전략을 사용하는 것을 권장함
** 참고
- 강의에서는 없지만 @GeneratedValue 전략에 UUID 전략도 적용할 수 있는데, UUID를 사용하여 기본키를 생성하는 전략임
- UUID(Universally Unique Identifier)는 128bit의 고유한 값으로 중복될 가능성이 극히 낮음
- UUID 전략은 분산 시스템에서 유용하며 데이터베이스 간 동기화에 이점이 있으나 가독성이 떨어지고 숫자 기반 ID에 비해 인덱싱 기능이 떨어질 수 있음
- 시퀀스는 1,2,3 처럼 단순한 값으로 증가하기 때문에 추정이 가능하지만 UUID는 추정이 거의 불가능하다는 장점이 있으나 대부분의 경우에서는 일반적인 것처럼 SEQUENCE나 IDENTITY 전략을 사용하며 데이터베이스를 샤딩하거나 여러 관계형 데이터베이스를 사용하여 특정 DB에 종속되는 시퀀스를 사용하기 어려운 애매한 상황이 등장하면 UUID를 고려해 볼 수 있음
- 데이터베이스 샤딩 : 대규모 데이터베이스를 여러개의 작은 파티션으로 분할하는 기술
5) 최적화 관련
- IDENTITY 전략에서 설명했듯이 DB에 INSERT SQL이 반영되어야 Id값을 알 수 있으므로 즉시 SQL쿼리를 DB에 날리게 설정되어 있어 영속성 컨텍스트의 기능 중 쿼리들을 모았다가 한번에 전송하는 SQL 쓰기 지연 저장소를 활용할 수 없다는 단점이 있는데 이부분이 비약적으로 성능 차이가 나지는 않음
- IDENTITY 전략을 제외하고는 실제 커밋하는 시점에 SQL쿼리가 DB에 전송 되는데, 시퀀스전략을 예를 들면 DB에 저장된 시퀀스 번호를 불러와야 영속성 컨텍스트에 저장할 수 있기때문에 시퀀스를 call을 해서 시퀀스 번호를 받아옴
- 이때 allocationSize가 1이면 매번 영속성 컨텍스트에 저장하는 시점에 시퀀스 번호를 불러와야하기 때문에 저장하는 갯수만큼 시퀀스 번호를 call을 하지만, allocationSize가 50이면(기본값 = 50) 미리 DB에 시퀀스를 50을 세팅해 놓고 메모리에서 1씩 꺼내서 쓰게 되어 미리 세팅된 수 만큼 시퀀스를 call하는 횟수를 줄어들게 할 수 있음
- 해당 옵션은 테이블 전략에서도 동일하게 적용됨
- 이론적으로 해당 값을 많이 적용하면 네트워크 호출 횟수가 줄어드니 좋을 수 있지만 너무 많이 해두면 예기치 않은 상황으로 데이터베이스가 종료되거나 시퀀스 번호에 구멍이 생기게 되어 보통 50 ~ 100정도로 설정함(시퀀스 번호에 간격이 생겨도 큰 문제는 없지만 불필요한 낭비가 될 수 있음)
- 서버가 여러대여서 10대가 동시에 호출되더라도 자신이 미리 시퀀스 번호를 확보해두었기 때문에 동시성 문제가 발생하지 않음
- hibernate 버전에 따라 시퀀스를 가져오는 동작이 call or select로 동작함(2019년 강의는 call이였으나 2024년 10월 6일 기준 hibernate 6.4.2.Final 버전 기준으로는 select로 동작했음)
5. 실전 예제 - 연관관계 매핑 시작
1) 요구사항 분석
- 회원은 상품을 주문할 수 있음
- 주문 시 여러 종류의 상품을 선택할 수 있음
- 실전 JPA - 웹 애플리케이션 개발 강의에서 다룬 요구사항과 동일함
2) 도메인 모델 분석
(1) 회원과 주문의 관계
- 회원은 여러 번 주문할 수 있음
- 일대다 관계
(2) 주문과 상품의 관계
- 주문할 때 여러 상품을 선택할 수 있음
- 같은 상품도 여러 번 주문 될 수 있음
- 주문상품 이라는 모델을 만들어서 다대다 관계를 이다대, 다대일 관계로 풀어냄
3) 테이블 설계, Entity 설계와 매핑
4) 코드
- 객체 설계를 테이블 설계에 맞춘 방식으로 코드를 설계
(1) 프로젝트 생성
- 빌드: Maven
- Java: 17
- pom.xml의 dependencies 의존성 주입설정과 JPA 설정인 persistence.xml은 기존 프로젝트의 설정을 복사해서 사용
(2) persistence.xml 수정
- persistence-unit의 이름을 변경하여 EntityManagerFactory의 이름과 매핑
- jdbc.url의 value를 수정하여 jpashop이라는 새로운 db로 접속
<!-- 기존 설정들 -->
<persistence-unit name="jpashop">
<!-- 기존 설정들 -->
<property name="jakarta.persistence.jdbc.url" value="jdbc:h2:tcp://localhost/~/jpashop"/>
<!-- 기존 설정들 -->
(2) Member
@Entity
public class Member {
@Id @GeneratedValue // GeneratedValue 전략을 기본값으로 설정(Auto)
@Column(name = "MEMBER_ID")
private Long id;
private String name;
private String city;
private String street;
private String zipcode;
// ... getter, setter들
}
(3) Item
@Entity
public class Item {
@Id @GeneratedValue
@Column(name = "ITEM_ID")
private Long id;
private String name;
private int price;
private int stockQuantity;
// ... getter, setter
}
(4) Order
@Entity
@Table(name = "ORDERS") // 주문은 ORDERS로 관례상 많이 씀
public class Order {
@Id @GeneratedValue
@Column(name = "ORDER_ID")
private Long id;
@Column(name = "MEMBER_ID")
private Long memberId; // Order 엔터티에 member의 id가 있음
private LocalDateTime orderDate;
@Enumerated(EnumType.STRING)
private OrderStatus status;
// ... getter, setter
}
(5) OrderItem
@Entity
@Table(name = "ORDER_ITEM")
public class OrderItem {
@Id @GeneratedValue
@Column(name = "ORDER_ITEM_ID")
private Long id;
@Column(name = "ORDER_ID")
private Long OrderId;
@Column(name = "ITEM_ID")
private Long ItemId;
private int orderPrice;
private int count;
// ... getter, setter
}
(6) OrderStatus - Enum
package jpabook.jpashop.domain;
public enum OrderStatus {
ORDER, CANCEL
}
(7) JpaMain 실행 결과
public class JpaMain {
public static void main(String[] args) {
EntityManagerFactory emf = Persistence.createEntityManagerFactory("jpashop");
EntityManager em = emf.createEntityManager();
EntityTransaction tx = em.getTransaction();
tx.begin();
try {
tx.commit();
} catch (Exception e) {
tx.rollback();
} finally {
em.close();
}
emf.close();
}
}
- 스프링 부트를 사용하지 않았으므로 필드명들이 자동 변환되지 않아서 직접 지정해주지 않은 필드는 그대로 DB에 반영되었음
** 참고사항
- 스프링부트를 사용하지 않은 상태에서 JPA를 사용하여 별도로 Table이나 Column의 이름을 지정하지 않은 필드명들은 그대로 DB에 매핑이 됨 -> 스프링 부트를 사용하지 않을 시 JPA 기본 매핑 전략
- 스프링 부트를 사용하여 프로젝트를 빌드하면 JPA 기본 매핑 전략설정이 카멜케이스(camelCase)를 스네이크케이스(snake_case)로 자동으로 변환하는 설정으로 빌드됨
- DB는 전통적으로 스네이크케이스를 사용함
- 예제여서 여기에는 적용하지 않았지만 실무에서는 메타데이터정보를 코드만 보고 제약조건, 인덱스 등을 수월하게 파악하도록 하기 위해 entity클래스에 매핑을 모두 적어주는 것이 좋으나 회사의 관례를 따라서 적용 하면됨
- 중요한 것은 일관성 있게 적용하는 것임
5) 데이터 중심 설계의 문제점
- 현재 방식은 객체 설계를 테이블 설계에 맞춘 방식으로 설계하여 테이블의 외래키를 객체에 그대로 가져옴
- em.find로 주문내역을 찾았을 때 이 주문내역에서 주문한 회원을 찾고자 하면 Order Entity에는 memberId 정보밖에 없으므로 memberId로 다시 em.find로 Member Entity에서 찾게됨
- 이러한 행위는 객체 지향적인 코드가 아니며 객체 그래프 탐색이 불가능하고 참조가 없으므로 설계한 UML 다이어그램처럼 동작하지 않음
- 객체지향 적으로 설계를 하려면 Order에 외래키가아닌 Member 객체 자체가 매핑이 되도록 설계해야하며 이렇게하면 주문을 조회했을때 바로 회원 정보가 남겨있으므로 회원에 대한정보를 별도의 em.find없이 바로 꺼낼 수 있음
- 이후에 배울 연관관계 매핑으로 객체지향적으로 코드를 설계를 할 수 있음
'인프런 - 스프링부트와 JPA실무 로드맵 > 자바 ORM 표준 JPA 프로그래밍 - 기본편' 카테고리의 다른 글
고급 매핑, 상속관계 매핑, Mapped Superclass - 매핑 정보 상속, 실전 예제 - 상속관계 매핑 (1) | 2024.10.11 |
---|---|
다양한 연관관계 매핑, 다대일[N:1], 일대다[1:N], 일대일[1:1], 다대다[N:M] 실전 예제 - 다양한 연관관계 매핑 (3) | 2024.10.10 |
연관관계 매핑 기초, 단방향 연관관계, 양방향 연관관계와 연관관계 주인(기본/주의점 및 정리), 실전 예제 - 연관관계 매핑 시작 (0) | 2024.10.08 |
영속성 관리 - 내부 동작 방식, 영속성 컨텍스트, 플러시, 준영속 상태 (2) | 2024.10.05 |
JPA 소개, SQL 중심적인 개발의 문제점, JPA 소개, JPA 시작하기, 프로젝트 생성, 애플리케이션 개발 (1) | 2024.10.04 |