@Entity
, @Table
@Column
@Id
@ManyToOne
, @JoinColumn
주의 🤚🏻
- 기본 생성자 필수(파라미터가 없는 public 또는 protected 생성자)
- final 클래스, enum, interface, inner 클래스 사용 X
- 저장할 필드에 final 사용 X
➡️ @Table
은 엔티티와 매핑할 테이블 지정
hibernate.hbm2ddl.auto
주의 🤚🏻
- **운영 장비에는 절대
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의 실행 로직에는 영향을 주지 않는다!
📌 요구사항 추가
1️⃣ 회원은 일반 회원과 관리자로 구분해야 한다.
2️⃣ 회원 가입일과 수정일이 있어야 한다.
3️⃣ 회원을 설명할 수 있는 필드가 있어야 한다. 이 필드는 길이 제한이 없다.
Member.java
수정
package hellojpa;
import javax.persistence.*;
import java.time.LocalDate;
import java.time.LocalDateTime;
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;
}
hibernate.hbm2ddl.auto
➡️ 자바 enum
타입을 매핑할 때 사용
➡️ 주의❗️ ORDINAL 사용 X
➡️ 날짜 타입(java.util.Date
, java.util.Calendar
)을 매핑할 때 사용
➡️ LocalDate
, LocalDateTime
을 사용할 때는 생략 가능(최신 하이버네이트 지원)
BLOB
, CLOB
타입과 매핑@Lob
에는 지정할 수 있는 속성이 없다.CLOB
매핑, 나머지는 BLOB
매핑@Transient
private Integer temp;
@Id
@GeneratedValue
1️⃣ 직접 할당 : @Id
만 사용
2️⃣ 자동 생성(@GeneratedValue
)
IDENTITY
: 데이터베이스에 위임, MYSQLSEQUENCE
: 데이터베이스 시퀀스 오브젝트 사용, ORACLE@SequenceGenerator
필요TABLE
: 키 생성용 테이블 사용, 모든 DB에서 사용@TableGenerator
필요AUTO
: 방언에 따라 자동 지정, 기본값📌 @TableGenerator - 속성
1️⃣ 테이블 생성
create table MY_SEQUENCES (
sequence_name varchar(255) not null,
next_val bigint,
primary key ( sequence_name )
)
2️⃣ Member.java
수정
@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;
회원기능
상품기능
주문기능
- 회원과 주문의 관계 : 회원은 여러 번 주문할 수 있다. (일대다)
- 주문과 상품의 관계 : 주문 할 때 여러 상품을 선택할 수 있다. 반대로 같은 상품도 여러 번 주문될 수 있다.
✔️ JpaMain
package jpabook.jpashop;
import jpabook.jpashop.domain.Member;
import jpabook.jpashop.domain.Order;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.EntityTransaction;
import javax.persistence.Persistence;
public class JpaMain {
public static void main(String[] args) {
// EntityManagerFactory
// 웹 서버가 올라오는 시점, 디비가 생성되는 시점에 딱 하나만 생성됨
// 쓰레드 간에 공유를 절대 해서는 안 된다
// JPA의 모든 데이터 변경은 트랜잭션 안에서 실행해야 한다
EntityManagerFactory emf = Persistence.createEntityManagerFactory("hello");
EntityManager em = emf.createEntityManager();
// 트랜잭션 생성
EntityTransaction tx = em.getTransaction();
// 데이터베이스 트랜잭션 시작
tx.begin();
try {
// 1. 주문을 찾는다
Order order = em.find(Order.class, 1L);
// 2. 그 주문을 한 멤버를 찾는다
Member findMember = order.getMember();
tx.commit();
} catch (Exception e) {
// 문제가 생겼을 경우 롤백
tx.rollback();
} finally {
// 실제 애플리케이션이 완전히 끝나면 종료
em.close();
}
emf.close();
}
}
✔️ Member
package jpabook.jpashop.domain;
import javax.persistence.*;
import static javax.persistence.GenerationType.AUTO;
@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;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getCity() {
return city;
}
public void setCity(String city) {
this.city = city;
}
public String getStreet() {
return street;
}
public void setStreet(String street) {
this.street = street;
}
public String getZipcode() {
return zipcode;
}
public void setZipcode(String zipcode) {
this.zipcode = zipcode;
}
}
✔️ Order
package jpabook.jpashop.domain;
import javax.persistence.*;
import java.time.LocalDateTime;
@Entity
@Table(name = "ORDERS")
public class Order {
@Id @GeneratedValue
@Column(name = "ORDER_ID")
private Long id;
// 누가 주문했는 지 알기 위함
@Column(name = "MEMBER_ID")
private Long memberId;
private Member member;
public Member getMember() {
return member;
}
private LocalDateTime orderDate;
// enum 타입은 무조건 string 으로
@Enumerated(EnumType.STRING)
private OrderStatus status;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public Long getMemberId() {
return memberId;
}
public void setMemberId(Long memberId) {
this.memberId = memberId;
}
public LocalDateTime getOrderDate() {
return orderDate;
}
public void setOrderDate(LocalDateTime orderDate) {
this.orderDate = orderDate;
}
public OrderStatus getStatus() {
return status;
}
public void setStatus(OrderStatus status) {
this.status = status;
}
}
나머지 클래스(
OrderItem
,Item
)도 요구사항에 맞춰 개발❗️
pom.xml
과persistence.xml
파일은 지난번에 실습했던 파일과 동일❗️
➡️ 단,persistence.xml
의 h2 데이터베이스 부분 이름을 jpashop 으로 변경
➡️ jpashop
이라는 새로는 h2 데이터베이스를 만들고, 실행하면 성공적으로 잘 반영됨 👍🏻
그런데❗️
상품을 주문한 사람을 찾고 싶을 때 위의 코드대로라면,
// Order.java
private Member member;
public Member getMember() {
return member;
}
⬆️ Order
에서 멤버를 찾는 메소드를 하나 만들고,
// JpaMain.java
try {
// 1. 주문을 찾는다
Order order = em.find(Order.class, 1L);
// 2. 그 주문을 한 멤버를 찾는다
Member findMember = order.getMember();
tx.commit();
}
⬆️ 메인 메소드에서 이와 같이 찾아야 하는데
이것은 뭔가 객체 지향스럽지 않다🤔
➡️ 객체보다는 관계형 데이터베이스에 의존하고 있음!!
➡️ 다음시간부터는 이를 해결할 수 있는연관 관계 매핑에 대해 배울 예정이다😀