@Entity
@Entity
가 붙은 클래스는 JPA가 관리@Entity
필수public
or protected
생성자)name
@Table
@Table
: 엔티티와 매핑할 DB의 테이블 지정
DDL(Data Definition Language)을 애플리케이션 실행 시점에 자동 생성
테이블 중싱 → 객체 중심
✨DB 방언을 활용해서 각 DB에 맞는 적절한 DDL 생성 → 생성된 DDL은 개발에서만 사용(운영 x)
속성
<property name="hibernate.hbm2ddl.auto" value="create" />
속성 값을 create
로 변경하고 애플리케이션을 실행했을 때
print:
Hibernate:
drop table Member if exists
Hibernate:
create table Member (
id bigint not null,
name varchar(255),
primary key (id)
)
💥주의
create
, create-drop
, update
를 사용하면 안된다.create
or update
update
or validate
validate
or none
DDL 생성 기능
제약조건 추가
ex) 회원 이름이 비어지면 안되고 크기는 10, 테이블의 name
이름을 "USERNAME"
@Column(name = "USERNAME", nullable = false, length = 10)
private String name;
DDL 생성 기능은 DDL을 자동 생성할 때만 사용되고 JPA 실행 로직에는 영향 X
요구사항 추가
1) 회원은 일반, 관리자로 구분
2) 회원 가입일과 수정일
3) 회원 설명 필드 (길이 제한 X)
package hellojpa;
import javax.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 createdDate;
@Temporal(TemporalType.TIMESTAMP)
private Date lastModifiedDate;
@Lob
private String description;
@Transient
private int temp;
protected Member(){
}
}
정리
✨@Column
: 컬럼 매핑
@Enumerated
: enum 타입 매핑
ORDINAL
사용 X → Why? 순서는 바뀔수가 있기 때문에.@Temporal
: 날짜 타입 매핑
LocalDate
or LocalDateTime
타입이면 해당 애노테이션(@Temporal
)이 필요 없다 ^^@Lob
: BLOB, CLOB 매핑 (큰 자료)
java.sql.CLOB
java.sql. BLOB
@Transient
: 특정 필드 매핑 X, 메모리상에서 임시로 어떤 값을 보관하고 싶을 때 사용
매핑 방법
직접 할당 : @Id
자동 생성(할당) : @GeneratedValue
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private String id;
@GeneratedValue
의 전략
⭕AUTO : (defalut) 방언에 따라 자동 지정
⭕IDENTITY
기본 키 생성을 DB에 위임 (DB가 값을 생성)
주로 MySQL, PostgreSQL, SQL Server, DB2에서 사용 (ex) MySQL의 AUTO_INCREMENT
)
예제)
Member
package hellojpa;
import javax.persistence.*;
@Entity
public class Member {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private String id;
@Column(name = "name", nullable = false)
private String username;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
}
JpaMain
의 try
try {
Member member = new Member();
member.setUsername("A");
em.persist(member);
tx.commit();
}
DB 결과
🧨제약 사항
IDENTITY 전략은 DB에 넣기 전까지는 기본 키값을 모른다. (=DB를 통해서만 PK를 확인할 수 있다.)
원래는, 1)em.persist(object)
를 통해서 영속성으로 만들고 2)tx.commit()
으로 쿼리를 날리지만 IDENTITY 전략은 1)을 통해서 쿼리를 먼저 날린다.
try {
Member member = new Member();
member.setUsername("A");
System.out.println("======================");
em.persist(member);
System.out.println("member.id = " + member.getId());
System.out.println("======================");
tx.commit();
}
print:
======================
Hibernate:
/* insert hellojpa.Member
*/ insert
into
Member
(id, name)
values
(null, ?)
member.id = 1
======================
//tx.commit() 시점이 아니라 em.persist(member) 시점에 쿼리를 보내고
//id(pk)를 받아올 수 있음을 보여준다.
⭕SEQUENCE (Type은 Long
추천)
유일한 값을 순서대로 생성하는 특별한 DB 오브젝트에서 값 생성
주로 오라클, PostgreSQL, DB2, H2 데이터베이스에서 사용
전략 - 매핑 (오브젝트(시퀀스) 생성)
package hellojpa;
import javax.persistence.*;
@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;
...
}
try {
Member member = new Member();
member.setUsername("A");
System.out.println("======================");
em.persist(member);
System.out.println("member.id = " + member.getId());
System.out.println("======================");
tx.commit();
}
실행 시, DB 모습
✨IDENTIY 전략은 .persist()
시, 쿼리가 날라가는 반면에 SEQUENCE 전략은 .persist()
시, SEQUENCE 전략인걸 알고 DB에서 값을 얻어와서 멤버(member.getId()
)에서 값을 얻어올 수 있다. 그 뒤 .commit()
시에 쿼리를 날린다.
SEQUENCE : 버퍼링(모았다가 한 번에 쓰기 가능)
IDENTITY : X
print:
======================
Hibernate:
call next value for MEMBER_SEQ
member.id = 1
======================
Hibernate:
/* insert hellojpa.Member
*/ insert
into
Member
(name, id)
values
(?, ?)
속성
allocationSize = 50
일 때!!
try {
Member member1 = new Member();
member1.setUsername("A");
Member member2 = new Member();
member2.setUsername("B");
Member member3 = new Member();
member3.setUsername("C");
System.out.println("======================");
em.persist(member1); // 1, 51
em.persist(member2); // memory
em.persist(member3); // memory
System.out.println("member1.id = " + member1.getId());
System.out.println("member2.id = " + member2.getId());
System.out.println("member3.id = " + member3.getId());
System.out.println("======================");
tx.commit();
}
print:
======================
Hibernate:
call next value for MEMBER_SEQ
Hibernate:
call next value for MEMBER_SEQ
member1.id = 1
member2.id = 2 (memory)
member3.id = 3 (memory)
======================
// 밑에는 쿼리를 보낸다.
// 두 번 호출된 이유는 51번까지 미리 확보하기위해서.
⭕TABLE (실무에서 잘 사용하지는 않는다.)
키 생성 전용 테이블을 하나 만들어 SEQUENCE 흉내
장점 : 모든 DB 적용 가능
단점 : 성능 이슈
전략 - 매핑 (Table 생성)
MY_SEQUENCES
create table MY_SEQUENCES (
sequence_name varchar(255) not null,
next_val bigint,
primary key ( sequence_name )
)
Member
@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;
}
속성
권장하는 식별자 전략
새 프로젝트 생성 후, persistence.xml
과 dependency
들 설정새 프로젝트 생성 후, persistence.xml과 dependency들 설정
데이터베이스 파일 생성 방법
~
: 해당 경로는 홈 디렉토리(C\Users{username}).
: h2 폴더 (H2\bin)요구사항
기능
도메인 모델 분석
테이블 & 엔티티 설계
테이블
엔티티
멤버
@Entity
public class Member {
@Id
@GeneratedValue
@Column(name = "MEMBER_ID")
private Long id;
private String name;
private String city;
private String street;
private String zipcode;
}
주문
@Entity
@Table(name = "ORDERS")
public class Order {
@Id
@GeneratedValue
@Column(name = "ORDER_ID")
private Long id;
@Column(name = "MEMBER_ID")
private Long memberId;
private LocalDateTime orderDate;
@Enumerated(EnumType.STRING)
private OrderStatus status;
}
주문상품
@Entity
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;
}
상품
@Entity
public class Item {
@Id
@GeneratedValue
@Column(name = "ITEM_ID")
private Long id;
private String name;
private int price;
private int stockQuantity;
}
데이터 중심 설계의 문제점
memberId