@Entity(name="MBR")
public class Member() {...}
@Table
의 name속성으로 넘겨받은 테이블을 찾고, 그 테이블과 엔티티를 연결한다.)JPA는 애플리케이션 로딩 시점에 데이터베이스 생성 기능도 지원하고 있다!
# Hibernate 설정
spring.jpa.hibernate.ddl-auto=update
application.properties
파일에 속성을 추가하고, 적절한 속성 값을 부여한다.
@Column(nullable = false, length = 10)
@Table(uniqueConstraints = (@UniqueConstraint(name = "NAME_AGE_UNIQUE", columnNames={"NAME", "AGE"} )});
@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 String description;
@Transient
private int temp;
public Member() {
}
// Getter, Setter ...
}
@Column
: 컬럼 매핑@Temporal
: 날짜 타입 매핑@Enumerated
: enum 타입 매핑@Lob
: BLOB, CLOB 매핑@Transient
: 특정 필드를 컬럼에 매핑하지 않음 (매핑 무시)EnumType.ORDINAL
인데, 이것은 Enum의 작성 순서를 기준으로 해 오류의 발생 가능성이 크다. 사용하지 않는 것을 추천한다.EnumType.ORDINAL
: enum 순서를 데이터베이스에 저장EnumType.STRING
: enum 이름을 데이터베이스에 저장.LocalDate
, LocalDateTime
을 사용할 때는 생략 가능하다. (최신 하이버네이트 지원)TemporalType.DATE
: 날짜, 데이터베이스 date 타입과 매핑TemporalType.TIME
: 시간, 데이터베이스 time 타입과 매핑TemporalType.TIMESTAMP
: 날짜와 시간, 데이터베이스 timestamp 타입과 매핑String, char[], java.sql.CLOB
byte[], java.sql.BLOB
@Transient
private Intege temp;
@Id @GeneratedValue(strategy = GenerationType.AUTY)
private Long id;
기본키를 직접 할당하는 경우 @Id
를 사용할 수 있다. 만약 자동으로 생성되는 seq같은 기본 키를 사용하고 싶은 경우를 위해 JPA에서 자동 생성 기능을 제공하고 있는데, @GeneratedValue
의 설정을 통해 사용할 수 있다.
@SequenceGenerator
필요@TableGenerator
필요@Entity
public class Member {
@Id
@GeneratedValue(strategy = GenerationType.IDNETITY)
private Long id;
}
em.persist()
시점에 즉시 INSERT SQL 실행하고 DB에서 식별자를 조회.em.persist()
시점에 바로 INSERT query를 전송한다.public static void main(String[] args) {
EntityManagerFactory emf = Persistence.createEntityManagerFactory();
EntityManager em = emf.createEntityManager()
EntityTransaction tx = em.getTransaction();
tx.begin();
try {
Member member = new Member();
member.setUsername("C");
System.out.println("===============");
em.persist(member); // DB에 바로 삽입 & PK 구하기
System.out.println("member.id = " + member.getId()); // 바로 직후 PK조회가 가능함.
System.out.println("===============");
tx.commit();
} catch (Exception e) {
}
===============
Hibernamte:
/* insert hellojpa.Member
*/ insert
into Member
(id, name)
values
(null, ?)
member.id = 1
===============
hibernate_sequence
값으로 seq가 들어간다.@Entity
@SequenceGeneratory(
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;
}
public static void main(String[] args) {
EntityManagerFactory emf = Persistence.createEntityManagerFactory();
EntityManager em = emf.createEntityManager()
EntityTransaction tx = em.getTransaction();
tx.begin();
try {
Member member = new Member();
member.setUsername("C");
System.out.println("===============");
em.persist(member); // DB에 바로 삽입 & PK 구하기
System.out.println("member.id = " + member.getId()); // 바로 직후 PK조회가 가능함.
System.out.println("===============");
tx.commit();
} catch (Exception e) {
}
Hibernate:
call next value for MEMBER_SEQ
member.id =1
===============
Hibernamte:
/* insert hellojpa.Member
*/ insert
into Member
(id, name)
values
(null, ?)
member.id = 1
===============
@Column(length = 10)
@Table(indexes = @Index())
인덱스 제약조건 표기 가능package com.study.jpashop.domain;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.Id;
@Entity
public class Member {
@Id @GeneratedValue
private Long id;
private String name;
private String city;
private String street;
private String zipcode;
}
package com.study.jpashop.domain;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.Id;
@Entity
public class Item {
@Id @GeneratedValue
@Column(name = "ITEM_ID")
private Long id;
private String name;
private int price;
private int stockQuantity;
}
package com.study.jpashop.domain;
import jakarta.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 LocalDateTime orderDate;
@Enumerated(EnumType.STRING)
private OrderStatus status;
}
package com.study.jpashop.domain;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.Id;
@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;
}
package com.study.jpashop.domain;
public enum OrderStatus {
ORDER, CANCEL;
}
외래키만 가지고 있는 테이블의 경우, 데이터를 조회하는 경우 id를 통해 테이블을 다시 조회해야 한다. 위의 예시에서 주문을 조회한 다음 주문과 연관된 회원을 조회하려면 외래키를 사용해 다시 조회해야 한다.
Order order = em.find(Order.class, orderId);
// 왜리키로 다시 조회
Member member = em.find(Member.class, order.getMemberId());
그러나 이와 달리, 참조를 사용해 연관된 객체를 조회하는 것이 객체지향적인 방법이다.
Order order = em.find(Order.class, orderId);
Member member = order.getMember(); // 참조사용
JPA는 객체의 참조와 테이블의 외래 키를 매핑해 객체에서는 참조를 사용하고 테이블에서는 외래 키를 사용할 수 있도록 한다. 다음 장을 통해 참조외 외래키를 어떻게 매핑하는지 알아보자.