Skip to content

Commit a140d37

Browse files
committed
Fix: Chapter04 해성 복구
1 parent 2160f71 commit a140d37

1 file changed

Lines changed: 297 additions & 0 deletions

File tree

chapter04/해성/Chapter04.md

Lines changed: 297 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,297 @@
1+
# 엔티티 매핑
2+
- 객체와 테이블 매핑 @Entity, @Table
3+
- 기본키 매핑 @Id
4+
- 필드와 컬럼 매핑 @Column
5+
- 연관관계 매핑 @ManyToOne, @JoinColumn
6+
7+
매핑정보는 xml 이나 어노테이션 중에 선택해서 기술하면 되는데 책에서는 어노테이션만 사용.
8+
어노테이션이 더 쉽고 직관적이다.
9+
10+
## @Entity
11+
@Entity 가 붙은 클래스는 JPA 가 관리
12+
### 속성
13+
- name : 기본값은 클래스 이름. 다른 패키지에 동일한 이름의 엔티티가 있으면 충돌하지 않게 해아함
14+
### 주의사항
15+
- 기본 생성자는 필수다 (public, protected)
16+
- final 클래스, enum, interface, inner 클래스에는 사용할 수 없다
17+
- 저장할 필드에 final 을 사용하면 안된다
18+
19+
## @Table
20+
- 엔티티와 매핑할 테이블을 지정
21+
- 생략하면 매핑한 엔티티 이름을 테이블 이름으로 지정
22+
### 속성
23+
- name : 테이블 이름. 기본값은 엔티티 이름
24+
- catalog : catalog 매핑
25+
- schema : schema 매핑
26+
- uniqueConstraints : ddl 을 만들 때만 사용
27+
28+
## 다양한 매핑 사용
29+
```java
30+
@Entity
31+
@Table(name="MEMBER")
32+
public class Member {
33+
34+
@Id
35+
@Column(name = "ID")
36+
private String id;
37+
38+
@Column(name = "NAME")
39+
private String username;
40+
41+
private Integer age;
42+
43+
@Enumerated(EnumType.STRING) // enum 을 사용하려면 @Enumerated 매핑
44+
private RoleType roleType;
45+
46+
@Temporal(TemporalType.TIMESTAMP) // 날짜 타입은 @Temporal 을 사용해서 매핑
47+
private Date createdDate;
48+
49+
@Temporal(TemporalType.TIMESTAMP)
50+
private Date lastModifiedDate;
51+
52+
@Lob
53+
private String description; // @Lob 을 사용하면 CLOB, BLOB 타입 매핑
54+
...
55+
}
56+
```
57+
## 데이터베이스 스키마 자동 생성
58+
### feature/h2
59+
```log
60+
Hibernate:
61+
drop table MEMBER if exists
62+
Hibernate:
63+
create table MEMBER (
64+
ID varchar(255) not null,
65+
age integer,
66+
createdDate timestamp,
67+
description clob,
68+
lastModifiedDate timestamp,
69+
roleType varchar(255),
70+
NAME varchar(10) not null,
71+
primary key (ID)
72+
)
73+
```
74+
75+
### feature/mysql
76+
```log
77+
Hibernate:
78+
drop table if exists MEMBER
79+
Hibernate:
80+
create table MEMBER (
81+
ID varchar(255) not null,
82+
age integer,
83+
createdDate datetime, # datetime
84+
description longtext, # longtext
85+
lastModifiedDate datetime,
86+
roleType varchar(255),
87+
NAME varchar(10) not null,
88+
primary key (ID)
89+
)
90+
```
91+
### hibernate.hbm2ddl.auto
92+
- create
93+
- create-drop
94+
- update
95+
- validate
96+
- none: *none 은 유효하지 않은 옵션 값이다.
97+
98+
### 이름 매핑 전략
99+
ImproveNamingStrategy: 테이블 명이나 컬럼 명이 생략되면 자바의 카멜 표기법을 테이블의 언더스코어 표기법으로 매핑
100+
101+
https://docs.jboss.org/hibernate/orm/current/userguide/html_single/Hibernate_User_Guide.html#naming
102+
103+
## DDL 생성 기능
104+
### @Column
105+
- nullable: 자동 생성되는 ddl 에 notnull 제약조건을 추가할 수 있음
106+
- length: 문자의 크기 지정할 수 있음
107+
### @Table
108+
- uniqueConstaint: 유니크 제약조건 추가
109+
110+
## 기본 키 매핑
111+
### 직접 할당
112+
- @Id 어노테이션 사용해서 기본키를 애플리케이션에서 할당
113+
### 자동 생성
114+
- IDENTITY: 기본 키 생성을 데이터베이스에 위임
115+
- SEQUENCE: 데이터베이스 시퀀스를 사용해서 기본 키를 할당
116+
- TABLE: 키 생성 테이블을 사용
117+
118+
SEQUENCE 나 IDENTITY 전략은 사용하는 데이터베이스에 의존함
119+
- oracle 은 시퀀스를 제공하지만 mysql 은 제공하지 않음
120+
- mysql 은 AUTO_INCREMENT 기능 제공
121+
122+
### hibernate.id.new_generator_mappings
123+
책에는 기본값 false, 현재는 true
124+
https://docs.jboss.org/hibernate/orm/current/userguide/html_single/Hibernate_User_Guide.html#configurations-mapping
125+
126+
하이버네이트 5부터 기본값이 true 임
127+
```
128+
By the way, starting with Hibernate 5 (which is in WildFly 10.0.0.Final), hibernate.id.new_generator_mappings defaults to true. I like the idea of being able to specify default persistence unit properties to be used, although I think that is a separate concern than the one raised by your post. Currently, you have to update all of your applications persistence.xml.
129+
```
130+
https://developer.jboss.org/thread/267613
131+
132+
### 기본키 직접 할당 전략
133+
em.persist() 로 엔티티를 저장하기 전에 애플리케이션에서 기본 키를 직접 할당하는 방식
134+
- 자바 기본형 (Primitive)
135+
- 자바 wrapper 형
136+
- String
137+
- java.util.Date
138+
- java.sql.Date (https://docs.oracle.com/javase/7/docs/api/java/sql/Date.html)
139+
- java.math.BigDecimal
140+
- java.math.BigInteger
141+
- java.util.UUID
142+
An interesting feature introduced in Hibernate 5 is the UUIDGenerator. To use this, all we need to do is declare an id of type UUID with @GeneratedValue annotation:
143+
```
144+
@Entity
145+
public class Course {
146+
147+
@Id
148+
@GeneratedValue
149+
private UUID courseId;
150+
151+
// ...
152+
}
153+
```
154+
https://www.baeldung.com/hibernate-identifiers
155+
156+
### IDENTITY 전략
157+
- 기본키 생성을 데이터베이스에 위임.
158+
- MySQL, PostgreSQL, SQL Server, DB2 에서 주로 사용
159+
160+
#### mysql auto_increment
161+
```sql
162+
CREATE TABEL BOARD (
163+
ID INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
164+
DATA VARCHAR(255)
165+
);
166+
INSERT INTO BOARD(DATE) VALUES('A');
167+
INSERT INTO BOARD(DATE) VALUES('B');
168+
```
169+
데이터베이스에 값을 저장할 때 ID 컬럼을 비워두면 데이터베이스가 순서대로 값을 채워준다
170+
171+
#### 최적화
172+
Statement.getGeneratedKeys() 를 사용하면 데이터를 저장하면서 동시에 생성된 기본 키 값도 얻어올 수 있다.
173+
하이버네이트는 이 메소드를 사용해서 데이터베이스와 한 번만 통신한다
174+
175+
#### 쓰기 지연
176+
IDENTITY 식별자 생성 전략은 엔티티를 데이터베이스에 저장해야 식별자를 구할 수 있으므로 em.persist() 를 호출하는 즉시 INSERT SQL 이 데이터베이스에 저장된다. 따라서 IDENTITY 전략에서는 트랜잭션을 지원하는 쓰기 지연이 동작하지 않는다.
177+
178+
### SEQUENCE 전략
179+
데이터베이스 시퀀스는 유일한 값을 순서대로 생성하는 특별한 데이터베이스 오브젝트다.
180+
181+
이 전략은 시퀀스를 지원하는 오라클, PostgreSQL, DB2, H2 데이터베이스에서 사용할 수 있다.
182+
183+
184+
코드는 IDENTITY 전략과 같지만 내부 동작 방식은 다르다.
185+
186+
SEQUENCE 전략은 em.persist() 를 호출할 때 먼저 데이터베이스 시퀀스를 사용해서 식별자를 조회한다.
187+
그리고 조회한 식별자를 엔티티에 할당한 후에 엔티티를 영속성 컨텍스트에 저장한다.
188+
이후 트랜잭션을 커밋해서 플러시가 일어나면 엔티티를 데이터베이스에 저장한다.
189+
반대로 이전에 설명했던 IDENTITY 전략은 먼저 엔티티를 데이터베이스에 저장한 후에 식별자를 조회해서 엔티티의 식별자에 할당한다.
190+
191+
#### @SequenceGenerator
192+
- name
193+
- sequenceName
194+
- initialValue
195+
- allocationSize
196+
- SequenceGenerator.allocationSize 의 기본값이 50인것에 주의.
197+
- 데이터베이스 시퀀스 값이 하나씩 증가하도록 설정되어 있으면 이 값을 반드시 1로 설정해야 한다.
198+
- catalog, schema
199+
200+
201+
#### mysql 에서 sequence 사용
202+
```log
203+
Hibernate:
204+
drop table if exists MEMBER
205+
Hibernate:
206+
drop table if exists hibernate_sequence
207+
Hibernate:
208+
create table MEMBER (
209+
ID bigint not null,
210+
age integer,
211+
createdDate datetime,
212+
description longtext,
213+
lastModifiedDate datetime,
214+
roleType varchar(255),
215+
NAME varchar(10) not null,
216+
primary key (ID)
217+
)
218+
Hibernate:
219+
alter table MEMBER
220+
add constraint NAME_AGE_UNIQUE unique (NAME, age)
221+
Hibernate:
222+
create table hibernate_sequence (
223+
next_val bigint
224+
)
225+
Hibernate:
226+
insert into hibernate_sequence values ( 1 )
227+
...
228+
229+
Hibernate:
230+
select
231+
next_val as id_val
232+
from
233+
hibernate_sequence for update
234+
235+
Hibernate:
236+
update
237+
hibernate_sequence
238+
set
239+
next_val= ?
240+
where
241+
next_val=?
242+
243+
Hibernate:
244+
/* insert jpabook.start.Member
245+
*/ insert
246+
into
247+
MEMBER
248+
(age, createdDate, description, lastModifiedDate, roleType, NAME, ID)
249+
values
250+
(?, ?, ?, ?, ?, ?, ?)
251+
...
252+
```
253+
254+
### TABLE 전략
255+
키 생성 전용 테이블을 하나 만들고 여기에 이름과 값으로 사용할 컬럼을 만들어 데이터베이스 시퀀스를 흉내내는 전략이다.
256+
시퀀스 대신에 테이블을 사용한다는 것만 제외하면 SEQUENCE 전략과 내부 동작방식이 같다.
257+
258+
```sql
259+
create table MY_SEQUENCES (
260+
sequence_name varchar(255) not null,
261+
next_val bigint,
262+
primary key ( sequence_name )
263+
)
264+
```
265+
266+
#### @TableGenerator
267+
- name
268+
- table
269+
- pkColumnName
270+
- valueColumnName
271+
- initialValue
272+
- allocationSize
273+
- catalog, schema
274+
- uniqueConstraints(DDL)
275+
276+
277+
### AUTO
278+
데이터베이스 방언에 따라 전략 중 하나를 자동으로 선택한다.
279+
예를 들어 오라클은 SEQUENCE, MySQL 은 IDENTITY 를 사용한다.
280+
281+
282+
## 필드와 컬럼 매핑: 레퍼런스
283+
필요할 때 코드, 주석, 문서를 보자.
284+
285+
## 정리
286+
생략
287+
288+
## 실전 예제 1. 요구사항 분석과 기본 매핑
289+
290+
291+
## 질문
292+
- 왜 기본생성자는 필수이고, public, protected 만 가능한지
293+
- 상속을 쓰나?
294+
- 저장할 필드에 왜 final 을 사용하면 안되는지
295+
- kotlin 은 val 써도되던데..
296+
- mysql auto_increment 어떻게 동작하는지
297+
- kotlin `@Id @GeneratedValue val id: Long = 0L` 으로 지정하면 query 어떻게 만들어지는지

0 commit comments

Comments
 (0)