이 글은 김영한의 [자바 ORM 표준 JPA 프로그래밍 - 기본편]을 수강하며 정리한 글입니다.
👉 기본 환경
- Language: Java
- DB: H2 Database
- IDE: IntelliJ
1. 기본키 직접 할당
1
2
3
4
5
6
7
|
@Entity
public class Member {
@Id // PK 지정 필수, PK 직접 할당
private Long id;
}
|
2. 기본키 자동 생성: @GeneratedValue
2.1. AUTO
- Default
- DB 방언에 맞춰 Value 자동 생성
2.2. IDENTITY
1
2
3
4
5
6
7
8
|
@Entity
public class Member {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
}
|
- PK 생성을 DB에 위임(예: MySQL: AUTO_INCREMENT)
- PK에 null값을 넘기면 DB에서 자동으로 생성해줌
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
|
public class Main {
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();
System.out.println("==========");
em.persist(member);
System.out.println("==========");
tx.commit();
} catch (Exception e) {
tx.rollback();
} finally {
em.close();
}
emf.close();
}
}
|
- JPA는 tx.commit() 시점에 INSERT SQL 실행
1
2
3
4
5
6
7
8
9
10
11
|
==========
Hibernate:
/* insert jpa_basic.Member
*/ insert
into
Member
(id)
values
(null)
==========
|
- IDENTITY 전략은 em.persist() 시점에 즉시 INSERT SQL 실행
- 영속성 컨텍스트에 의해 관리되기 위해서 (Key, Value)로 (PK, 객체) 값이 필요한데, 영속성 컨텍스트에 관리되는 시점인 persist 시, PK값을 알 수 없으므로 IDENTITY 전략만 예외적으로 persist에서 DB insert query 발생
2.3. SEQUENCE
1
2
3
4
5
6
7
8
9
10
11
12
13
|
@Entity
@SequenceGenerator(
name = "MEMBER_SEQ_GENERATOR", // Java에서의 SEQ 이름
sequenceName = "MEMBER_SEQ", // DB에서의 SEQ 이름
allocationSize = 3
)
public class Member {
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "MEMBER_SEQ_GENERATOR")
private Long id;
}
|
- Sequence 객체를 생성해서 생성한 Sequence 객체에서 값을 가져와 PK값에 세팅
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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
|
public class Main {
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();
System.out.println("=====11=====");
em.persist(member1);
System.out.println("=====22=====");
Member member2 = new Member();
Member member3 = new Member();
Member member4 = new Member();
Member member5 = new Member();
Member member6 = new Member();
Member member7 = new Member();
Member member8 = new Member();
em.persist(member2);
em.persist(member3);
em.persist(member4);
System.out.println("=====33=====");
em.persist(member5);
em.persist(member6);
em.persist(member7);
System.out.println("=====44=====");
em.persist(member8);
System.out.println("=====55=====");
tx.commit();
} catch (Exception e) {
tx.rollback();
} finally {
em.close();
}
emf.close();
}
}
|
- em.persist() 실행 시, 영속성 컨텍스트에 의해 관리되기 위해서 IDENTITY 전략과 마찬가지로 PK 값을 필요로 함
- 그러나, SEQUENCE 객체도 DB에 의해 관리되므로 PK를 알 수 없음
- 그러므로, em.persist(); 시 SEQ 객체로부터 PK값을 얻어옴
⭐ Insert 시점은 commit 시점으로 query buffer 기능 사용 가능
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
=====11=====
Hibernate:
call next value for MEMBER_SEQ
Hibernate:
call next value for MEMBER_SEQ
=====22=====
=====33=====
Hibernate:
call next value for MEMBER_SEQ
=====44=====
Hibernate:
call next value for MEMBER_SEQ
=====55=====
Hibernate:
/* insert jpa_basic.Member
*/ insert
into
Member
(id)
values
(?)
...
|
- 처음에 call next value가 2번 호출되는 이유
- SEQ 객체 초기 값이 -2로 call next value를 호출하여, 1부터 시작될 수 있도록 setting
- allocationSize에 따라 메모리에 미리 seq값을 저장해두기 위해 호출
- 그 이후서부터는 미리 저장해둔 seq를 다 사용하면 call next value
2.4. TABLE
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
@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
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
|
public class Main {
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();
System.out.println("==========");
em.persist(member);
System.out.println("==========");
tx.commit();
} catch (Exception e) {
tx.rollback();
} finally {
em.close();
}
emf.close();
}
}
|
- 테이블을 직접 생성하므로 모든 데이터베이스에 적용 가능하나, 최적화 등 성능 문제가 발생할 수 있음
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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
|
Hibernate:
create table Member (
id bigint not null,
primary key (id)
)
Hibernate:
create table MY_SEQUENCES (
sequence_name varchar(255) not null,
next_val bigint,
primary key (sequence_name)
)
Hibernate:
insert into MY_SEQUENCES(sequence_name, next_val) values ('MEMBER_SEQ',0)
=====11=====
Hibernate:
select
tbl.next_val
from
MY_SEQUENCES tbl
where
tbl.sequence_name=? for update
Hibernate:
update
MY_SEQUENCES
set
next_val=?
where
next_val=?
and sequence_name=?
Hibernate:
select
tbl.next_val
from
MY_SEQUENCES tbl
where
tbl.sequence_name=? for update
Hibernate:
update
MY_SEQUENCES
set
next_val=?
where
next_val=?
and sequence_name=?
=====22=====
Hibernate:
/* insert jpa_basic.Member
*/ insert
into
Member
(id)
values
(?)
|
📚 참고 자료
'Java > JPA' 카테고리의 다른 글
[JPA_Basic] 양방향 매핑 시, 값이 입력되지 않는 경우 (0) | 2023.08.13 |
---|---|
[JPA_Basic] 객체 지향 모델링 (0) | 2023.08.08 |
[JPA_Basic] 데이터베이스 스키마 자동 생성 (0) | 2023.07.31 |
[JPA_Basic] Persistence Context 장점 (0) | 2023.07.29 |
[JPA] @PrePersist (0) | 2023.06.25 |