Member class 이렇게 해서 시작해보자.
@Entity
public class Member {
@Id
private Long id;
@Column(name = "name", nullable = false)
private String username;
public Member() {
}
}
사용할 수 있는 Annotation은 크게 두 가지가 있다.
- @Id
- @GeneratedValue
기본 키 매핑 방법
- 직접 할당: @Id만 사용
- 자동 생성(@GeneratedValue)
id를 string으로 해놓고
id를 직접 할당한다 그러면 아래와 같이 작성
// Member class
package hellojpa;
import javax.persistence.*;
@Entity
public class Member {
@Id
private String id;
@Column(name = "name", nullable = false)
private String username;
public Member() {
}
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 class
package hellojpa;
import org.hibernate.Hibernate;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.EntityTransaction;
import javax.persistence.Persistence;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Root;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Set;
public class JpaMain {
public static void main(String[] args) {
EntityManagerFactory emf = Persistence.createEntityManagerFactory("hello");
EntityManager em = emf.createEntityManager();
EntityTransaction tx = em.getTransaction();
tx.begin();
try {
Member member = new Member();
member.setId("ID_A");
member.setUsername("C");
em.persist(member);
tx.commit();
} catch (Exception e) {
tx.rollback();
} finally {
em.close();
}
emf.close();
}
}
GenerationType.AUTO는 DB방언에 따라 자동으로 생성
@Entity
public class Member {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private String id;
@Column(name = "name", nullable = false)
private String username;
public Member() {
}
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;
}
}
- IDENTITY: 데이터베이스에 위임
- 주로 MYSQL, PostgreSQL, SQL Server, DB2에서 사용(DB2에서 사용) => mysql의 AUTO_INCREMENT
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 Member() {
}
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;
}
}
아래 구문을 mysql 방언으로 바꾸면
Hibernate:
create table Member (
id varchar(255) generated by default as identity,
name varchar(255) not null,
TEAM_ID bigint,
primary key (id)
)
아래와 같이 이렇게 빌드값이 나온다.
Hibernate:
create table Member (
id varchar(255) not null auto_increment,
name varchar(255) not null,
TEAM_ID bigint,
primary key (id)
) engine=MyISAM
- SEQUENCE: 데이터베이스 시퀀스 오브젝트 사용, ORACLE
- @SequenceGenerator 필요
오브젝트를 만들어낸다.
Hibernate:
drop sequence if exists hibernate_sequence
Hibernate: create sequence hibernate_sequence start with 1 increment by 1
Hibernate:
이후에 call을 해서 값을 불러온다.
Hibernate:
call next value for hibernate_sequence
id를 String에서 Long으로 바꿔주고 빌드 한번 해주고
package hellojpa;
import javax.persistence.*;
@Entity
public class Member {
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE)
private Long id;
@Column(name = "name", nullable = false)
private String username;
public Member() {
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
}
persistence.xml에서 ddl.auto값을 create 에서 none으로 바꿔준다음 다시 돌려준다.
그러면 아래와 같이 h2 db에 세팅이 된다.
<property name="hibernate.hbm2ddl.auto" value="none" />
이제 SequenceGenerator를 써보면
@Entity
@SequenceGenerator(name = "member_sqe_generator", sequenceName = "member_seq")
public class Member {
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "member_sqe_generator")
private Long id;
@Column(name = "name", nullable = false)
private String username;
public Member() {
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
}
persistence.xml
<property name="hibernate.hbm2ddl.auto" value="create" />
TABLE 전략
- TABLE: 키 생성용 테이블 사용, 모든 DB에서 사용
- @TableGenerator 필요
- AUTO: 방언에 따라 자동 지정, 기본값
- 키 생성 전용 테이블을 하나 ㅁ나들어서 데이터베이스 시퀀스를 흉내내는 전략
- 장점 : 모든 데이터베이스에 적용 가능
- 단점 : 테이블을 직접 사용하니까 성능이 좋지 않음(최적화가 되지않음)
TableGenerator을 직접 써보면 빌드기 아래와 같이 나온다.
@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;
@Column(name = "name", nullable = false)
private String username;
public Member() {
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
}
계속 실행시키면 NEXT_VAL이 증가하게 될 것이다.
Hibernate:
create table MY_SEQUENCES (
sequence_name varchar(255) not null,
next_val bigint,
primary key (sequence_name)
)
TableGenerator - 속성 중에서 아래 두개가 중요하다.
권장하는 식별자 전략
- 기본 키 제약 조건: null 아니고 유일하면서 변하면 안된다.
- 미래까지 조건을 만족하는 자연키(주민번호, 전화번호)는 찾기 어렵다. 대리키(대체키)를 이용하자.
- 예를 들어 주민등록번호도 기본 키로 적절하지 않고
- 권장: Long형 + 대체키(ex) UUID) + 키 생성전략 사용
다시 IDENTITY 전략으로 넘어오고
여기서 일단 영속성 파트를 참고해보자. 1차 캐시 파트 부분에서 @Id가 db에 있는 pk 값이 된다.
하지만 Identity는 db에 넣기 전까지 이 값(member1)을 모른다.
Member class
package hellojpa;
import javax.persistence.*;
@Entity
public class Member {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(name = "name", nullable = false)
private String username;
public Member() {
}
}
그래서 IDENTITY 전략에서만 예외적으로
아래를 호출하자마자 db에 insert 쿼리를 날린다.
em.persist(member);
Hibernate:
/* insert hellojpa.Member
*/ insert
into
Member
(id, name)
values
(null, ?)
아래와 같이 실행시켜주면 db가 생성한 값을 읽어온다.
public class JpaMain {
public static void main(String[] args) {
EntityManagerFactory emf = Persistence.createEntityManagerFactory("hello");
EntityManager em = emf.createEntityManager();
EntityTransaction tx = em.getTransaction();
tx.begin();
try {
Member member = new Member();
member.setUsername("C");
System.out.println("=================");
em.persist(member);
System.out.println("member.id = " + member.getId());
System.out.println("=================");
tx.commit();
} catch (Exception e) {
tx.rollback();
} finally {
em.close();
}
emf.close();
}
}
만약 IDENTITY를 설정하지 않고 SEQUENCE나 다른 전략을 쓰게 되면 persist가 아닌 실제 commit하는 부분에서 쿼리가 날라가게 된다.
allocationSize = 1을 주는 아래와 같은 매핑전략을 쓰게되면 1부터 시작해서 1씩 증가시켜라고 한다.
sequence object가 1씩 증가시켜라고 세팅을 해준다.
package hellojpa;
import javax.persistence.*;
@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;
@Column(name = "name", nullable = false)
private String username;
public Member() {
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
}
Hibernate: create sequence hibernate_sequence start with 1 increment by 1
allocationSize = 50으로 주고 해보자.
package hellojpa;
import javax.persistence.*;
@Entity
@TableGenerator(
name = "MEMBER_SEQ_GENERATOR",
table = "MY_SEQUENCES",
pkColumnValue = "MEMBER_SEQ", allocationSize = 50)
public class Member {
@Id
@GeneratedValue(strategy = GenerationType.TABLE,
generator = "MEMBER_SEQ_GENERATOR")
private Long id;
@Column(name = "name", nullable = false)
private String username;
public Member() {
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
}
// DB SEQ = 1 | 1
// DB SEQ = 51 | 2
// DB SEQ = 51 | 3
51번이 일어난 다음에 next call이 일어난다.
나중에 다시 정리를 해본다.
package hellojpa;
import org.hibernate.Hibernate;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.EntityTransaction;
import javax.persistence.Persistence;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Root;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Set;
public class JpaMain {
public static void main(String[] args) {
EntityManagerFactory emf = Persistence.createEntityManagerFactory("hello");
EntityManager em = emf.createEntityManager();
EntityTransaction tx = em.getTransaction();
tx.begin();
try {
Member member1 = new Member();
member1.setUsername("A");
Member member2 = new Member();
member1.setUsername("B");
Member member3 = new Member();
member1.setUsername("C");
System.out.println("=================");
em.persist(member1); // 1, 51
em.persist(member2); // MEMORY
em.persist(member3); // MEMORY
System.out.println("member1 = " + member1.getId());
System.out.println("member2 = " + member2.getId());
System.out.println("member3 = " + member3.getId());
System.out.println("=================");
tx.commit();
} catch (Exception e) {
tx.rollback();
} finally {
em.close();
}
emf.close();
}
}
<출처 김영한: 자바 ORM 표준 JPA 프로그래밍 - 기본편 >
https://www.inflearn.com/course/ORM-JPA-Basic/dashboard
자바 ORM 표준 JPA 프로그래밍 - 기본편 - 인프런 | 강의
JPA를 처음 접하거나, 실무에서 JPA를 사용하지만 기본 이론이 부족하신 분들이 JPA의 기본 이론을 탄탄하게 학습해서 초보자도 실무에서 자신있게 JPA를 사용할 수 있습니다., - 강의 소개 | 인프런
www.inflearn.com
'Spring > JPA' 카테고리의 다른 글
연관관계 매핑 기초 - 단방향 연관관계 (0) | 2022.04.16 |
---|---|
실전 예제 1 - 요구사항 분석과 기본 매핑 (0) | 2022.04.14 |
필드와 컬럼 매핑 (0) | 2022.04.14 |
데이터베이스 스키마 자동 생성 (0) | 2022.04.14 |
엔티티 매핑 - 객체와 테이블 매핑 (0) | 2022.04.14 |