JPA ๊ณต๋ถ€

Park sang wooยท2022๋…„ 8์›” 23์ผ
0

์ธํ”„๋Ÿฐ ๊ณต๋ถ€

๋ชฉ๋ก ๋ณด๊ธฐ
2/8

๐Ÿ“– ORM

Object-relational mapping(๊ฐ์ฒด ๊ด€๊ณ„ ๋งคํ•‘)
ํ”„๋กœ๊ทธ๋ž˜๋ฐ ์–ธ์–ด์˜ ๊ฐ์ฒด์™€ ๊ด€๊ณ„ํ˜• ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์˜ ๋ฐ์ดํ„ฐ๋ฅผ ์ž๋™์œผ๋กœ ๋งคํ•‘(์—ฐ๊ฒฐ)ํ•ด์ฃผ๋Š” ๋„๊ตฌ์ด๋‹ค.

๊ฐ์ฒด๋Š” ๊ฐ์ฒด๋Œ€๋กœ ์„ค๊ณ„ํ•˜๊ณ  ๊ด€๊ณ„ํ˜• ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค๋Š” ๊ด€๊ณ„ํ˜• ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค๋Œ€๋กœ ์„ค๊ณ„.






๐Ÿ“– JPA

Java ์ง„์˜์—์„œ ORM(Object-Relational Mapping) ๊ธฐ์ˆ  ํ‘œ์ค€์œผ๋กœ ์‚ฌ์šฉํ•˜๋Š” ์ธํ„ฐํŽ˜์ด์Šค ๋ชจ์Œ์œผ๋กœ ์ž๋ฐ” ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜์—์„œ ๊ด€๊ณ„ํ˜• ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๋ฐฉ์‹์„ ์ •์˜ํ•œ ์ธํ„ฐํŽ˜์ด์Šค์ด๋‹ค.


**์‚ฌ์šฉ ์ด์œ **

1. ๋ฐ˜๋ณต์ ์ธ CRUD SQL์„ ์ฒ˜๋ฆฌํ•ด์ค€๋‹ค. -> ์ƒ์‚ฐ์„ฑ
์ €์žฅ : jpa.persist(member)
์กฐํšŒ : Member member = jpa.find(memberId)
์ˆ˜์ • : member.setName("๋ณ€๊ฒฝํ•  ์ด๋ฆ„")
์‚ญ์ œ : jpa.remove(member)


2. ์œ ์ง€๋ณด์ˆ˜ => ๊ธฐ์กด์—๋Š” ํ•„๋“œ ๋ณ€๊ฒฝ ์‹œ ๋ชจ๋“  SQL์„ ์ˆ˜์ •ํ–ˆ์ง€๋งŒ JPA๋Š” ํ•„๋“œ๋งŒ ์ถ”๊ฐ€ํ•˜๋ฉด ๋œ๋‹ค. ์ฆ‰ SQL์€ JPA๊ฐ€ ์ฒ˜๋ฆฌํ•ด์ค€๋‹ค.


3. ์ƒ์†, ์—ฐ๊ด€๊ด€๊ณ„, ๊ฐ์ฒด ๊ทธ๋ž˜ํ”„ ํƒ์ƒ‰, ๋น„๊ตํ•˜๊ธฐ ๊ฐ™์€ ํŒจ๋Ÿฌ๋‹ค์ž„ ๋ถˆ์ผ์น˜ ํ•ด๊ฒฐํ•ด์ค€๋‹ค.

JPA์™€ ์ƒ์† - ์ €์žฅ
๊ฐœ๋ฐœ์ž์˜ ์ผ -> jpa.persist(album);
JPA ์ฒ˜๋ฆฌ -> INSERT INTO ITEM, INSERT INTO ALBUM

JPA์™€ ์ƒ์† - ์กฐํšŒ
๊ฐœ๋ฐœ์ž์˜ ์ผ -> Album album = jpa.find(Album.class, albumId);
JPA ์ฒ˜๋ฆฌ
-> SELECT I., A.
FROM ITEM I
JOIN ALBUM A ON I.ITEM_ID = A.ITEM_ID


์‹ ๋ขฐํ•  ์ˆ˜ ์žˆ๋Š” ์—”ํ‹ฐํ‹ฐ, ๊ณ„์ธต

๋น„๊ตํ•˜๊ธฐ

String memberId = "100";
Member member1 = jpa.find(Member.class, memberId);
Member member2 = jpa.find(Member.class, memberId);

member1 == member2; //true

๋™์ผํ•œ ํŠธ๋žœ์žญ์…˜์—์„œ ์กฐํšŒํ•œ ์—”ํ‹ฐํ‹ฐ๋Š” ๊ฐ™์Œ์„ ๋ณด์žฅํ•œ๋‹ค.


JPA์˜ ์„ฑ๋Šฅ ์ตœ์ ํ™” ๊ธฐ๋Šฅ

  1. 1์ฐจ ์บ์‹œ์™€ ๋™์ผ์„ฑ ๋ณด๋‹น
    ๊ฐ™์€ ํŠธ๋žœ์žญ์…˜ ์•ˆ์—์„œ๋Š” ๊ฐ™์€ ์—”ํ‹ฐํ‹ฐ๋ฅผ ๋ฐ˜ํ™˜ํ•œ๋‹ค.

  2. ํŠธ๋žœ์žญ์…˜์„ ์ง€์›ํ•˜๋Š” ์“ฐ๊ธฐ ์ง€์—ฐ
    ํŠธ๋žœ์žญ์…˜์„ ์ปค๋ฐ‹ํ•  ๋•Œ๊นŒ์ง€ INSERT SQL์„ ๋ชจ์šธ ์ˆ˜ ์žˆ๋‹ค.
    JDBC BATCH SQL ๊ธฐ๋Šฅ๋ฅผ ์‚ฌ์šฉํ•ด์„œ ํ•œ ๋ฒˆ์— SQL ์ „์†กํ•œ๋‹ค.

  3. ์ง€์—ฐ ๋กœ๋”ฉ
    ์ง€์—ฐ๋กœ๋”ฉ์€ ๊ฐ์ฒด๊ฐ€ ์‹ค์ œ ์‚ฌ์šฉ๋  ๋•Œ ๋กœ๋”ฉํ•˜๋Š” ๊ฒƒ์ด๊ณ  ์ฆ‰์‹œ ๋กœ๋”ฉ์€ JOIN SQL๋กœ ํ•œ ๋ฒˆ์— ์—ฐ๊ด€๋œ ๊ฐ์ฒด๊นŒ์ง€ ๋ฏธ๋ฆฌ ์กฐํšŒํ•œ๋‹ค.

Hibernate๋Š” JPA๋ฅผ ๊ตฌํ˜„ํ•œ ๊ตฌํ˜„์ฒด.






๐Ÿ“ƒ em.persist()

์˜์†์„ฑ ์ปจํ…์ŠคํŠธ๋ฅผ ํ†ตํ•ด์„œ ์—”ํ‹ฐํ‹ฐ๋ฅผ ์˜์†ํ™” ํ•œ๋‹ค๋Š” ๋œป์ด๋‹ค. ๊ฐ์ฒด๋ฅผ ์ €์žฅํ•œ ์ƒํƒœ๊ฐ€ ๋จ.


๐Ÿ“ƒ @Entity

JPA๊ฐ€ ๊ด€๋ฆฌํ•˜๋Š” ๊ฐ์ฒด๊ณ  DB ํ…Œ์ด๋ธ”๊ณผ ๋งคํ•‘ํ•œ๋‹ค.
JPA๋ฅผ ์‚ฌ์šฉํ•ด์„œ ํ…Œ์ด๋ธ”๊ณผ ๋งคํ•‘ํ•  ํด๋ž˜์Šค๋Š” ํ•„์ˆ˜๋กœ ์จ์•ผํ•œ๋‹ค.
(๊ธฐ๋ณธ ์ƒ์„ฑ์ž ํ•„์ˆ˜)


๐Ÿ“ƒ @Entity(name = "")

๋‹ค๋ฅธ ํŒจํ‚ค์ง€์— ๊ฐ™์€ ์ด๋ฆ„์˜ ํด๋ž˜์Šค๊ฐ€ ๋งคํ•‘์ด ๋˜์–ด์žˆ์„ ๋•Œ ์‚ฌ์šฉ


๐Ÿ“ƒ @Table

์—”ํ‹ฐํ‹ฐ์™€ ๋งคํ•‘ํ•  ํ…Œ์ด๋ธ” ์ง€์ •
(name = "MBR") ์ผ๊ฒฝ์šฐ "MBR" ์ด๋ผ๋Š” ํ…Œ์ด๋ธ”๊ณผ ๋งคํ•‘ํ•œ๋‹ค. <ํ…Œ์ด๋ธ” ๋ช…์„ ์ •ํ•ด์คŒ>


๐Ÿ“ƒ @EqualsAndHashCode


๐Ÿ“ƒ @NoArgsConstructor

ํŒŒ๋ผ๋ฏธํ„ฐ๊ฐ€ ์—†๋Š” ๊ธฐ๋ณธ์ƒ์„ฑ์ž๋ฅผ ๋งŒ๋“ค์–ด์ค€๋‹ค.


๐Ÿ“ƒ @AllArgsContructor

๋ชจ๋“  ํ•„๋“œ ๊ฐ’์„ ํŒŒ๋ผ๋ฏธํ„ฐ๋กœ ๋ฐ›๋Š” ์ƒ์„ฑ์ž๋ฅผ ๋งŒ๋“ค์–ด์คŒ.


๐Ÿ“ƒ @RequiredArgsConstructor

final์ด๋‚˜ @NonNull์ธ ํ•„๋“œ ๊ฐ’๋งŒ ํŒŒ๋ผ๋ฏธํ„ฐ๋กœ ๋ฐ›๋Š” ์ƒ์„ฑ์ž ๋งŒ๋“ค์–ด์คŒ.


๐Ÿ“ƒ @Id

๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ๊ธฐ๋ณธํ‚ค(PK)์™€ ๋งคํ•‘


๐Ÿ“ƒ @Column

์ปฌ๋Ÿผ๋ช…์œผ๋กœ name = "" ๋ผ๊ณ  ์ค„ ์ˆ˜ ์žˆ๋‹ค.
unique๋Š” @Table ์— ์žˆ๋Š” ๊ฒƒ์ด ๋” ์ข‹์Œ
ex)@Table(uniqueConstraints = "")


๐Ÿ“ƒ insertable, updatable

๋“ฑ๋ก, ๋ณ€๊ฒฝ ๊ฐ€๋Šฅ ์—ฌ๋ถ€ (true, false)


๐Ÿ“ƒ nullable

null ๊ฐ’์˜ ํ—ˆ์šฉ ์—ฌ๋ถ€๋ฅผ ์„ค์ •
(false๋กœ ์„ค์ •ํ•˜๋ฉด DDL ์ƒ์„ฑ ์‹œ์— not null ์ œ์•ฝ์กฐ๊ฑด์ด ๋ถ™๋Š”๋‹ค)


๐Ÿ“ƒ columnDefinition

DB ์ปฌ๋Ÿผ ์ •๋ณด๋ฅผ ์ง์ ‘ ์ค„ ์ˆ˜ ์žˆ๋‹ค.
ex) columnDefinition = "varchar(100) default 'EMPTY'"


๐Ÿ“ƒ length = ์ˆซ์ž

varchar(์ˆซ์ž)


๐Ÿ“ƒ precision, scale

BigDecimal ํƒ€์ž…์—์„œ ์‚ฌ์šฉํ•œ๋‹ค. (BigInteger ๋„ ์‚ฌ์šฉ ๊ฐ€๋Šฅ)
precision์€ ์†Œ์ˆ˜์ ์„ ํฌํ•จํ•œ ์ „์ฒด ์ž๋ฆฟ์ˆ˜๋ฅผ, scale์€ ์†Œ์ˆ˜ ์ž๋ฆฟ์ˆ˜ (double, float ํƒ€์ž…์—๋Š” ์ ์šฉ๋˜์ง€ ์•Š๋Š”๋‹ค.)
์ •๋ฐ€ํ•œ ์†Œ์ˆ˜๋ฅผ ๋‹ค๋ฃฐ ๋•Œ ์‚ฌ์šฉ


๐Ÿ“ƒ @CreationTimestamp


๐Ÿ“ƒ JpaRepository<MemberEntity, Long>


๐Ÿ“ƒ @SpringBootTest


๐Ÿ“ƒ @Transactional


๐Ÿ“ƒ Transactional(readOnly = true)

์ฝ๊ธฐ ์ „์šฉ์œผ๋กœ ๋ฐ์ดํ„ฐ ๋ณ€๊ฒฝ์ด ๋˜์ง€ ์•Š๊ฒŒ ํ•˜๊ธฐ ์œ„ํ•ด ์‚ฌ์šฉ.
์กฐํšŒ์—์„œ ์ž์ฃผ ์‚ฌ์šฉ.


๐Ÿ“ƒ @ManyToOne, @JoinColumn

์—ฐ๊ด€๊ด€๊ณ„ ๋งคํ•‘.
ex) ํšŒ์›์ด ์–ด๋Š ํŒ€์— ์†Œ์†๋˜์–ด ์žˆ๋Š”์ง€์˜ ๊ด€๊ณ„๋ฅผ ๋งคํ•‘


๐Ÿ“ƒ IllegalArgumentException vs IllegalStateException

IllegalArgumentException
์ ์ ˆํ•˜์ง€ ์•Š๊ฑฐ๋‚˜ ์œ ํšจํ•˜์ง€ ์•Š์€ ๋ฐ์ดํ„ฐ๋ฅผ ๋ฐ›์•˜์„ ๋•Œ ๋ฐœ์ƒํ•˜๋Š” ์˜ˆ์™ธ ex) ์–‘์ˆ˜๋ฅผ ํŒŒ๋ผ๋ฏธํ„ฐ๋กœ ๊ธฐ๋Œ€ํ•˜๊ณ  ์žˆ์—ˆ๋Š”๋ฐ ์Œ์ˆ˜๊ฐ€ ๋„˜์–ด์˜ด.

IllegalStateException
์ ์ ˆํ•˜์ง€ ์•Š๊ฑฐ๋‚˜ ์œ ํšจํ•˜์ง€ ์•Š์€ ์‹œ๊ฐ„๋Œ€์— ๋ฉ”์†Œ๋“œ๊ฐ€ ๋ถˆ๋Ÿฌ์กŒ์„ ๋•Œ ๋ฐœ์ƒํ•˜๋Š” ์˜ˆ์™ธ ex) ์ฃฝ์€ ์“ฐ๋ ˆ๋“œ๋กœ๋ถ€ํ„ฐ ๋ถˆ๋ ค์ง€๋Š” ๊ฒฝ์šฐ์™€ ๊ฐ™์ด ๋ฉ”์†Œ๋“œ๊ฐ€ ๋ถˆ๋ ค์ ธ์„œ ์•ˆ๋  ์‹œ๊ธฐ์— ๋ฉ”์†Œ๋“œ๊ฐ€ ํ˜ธ์ถœ๋  ๋•Œ ๋ฐœ์ƒ
-> ๋ฉ”์†Œ๋“œ๊ฐ€ ์š”๊ตฌ๋œ ์ฒ˜๋ฆฌ๋ฅผ ํ•˜๊ธฐ์— ์ ํ•ฉํ•œ ์ƒํƒœ์— ์žˆ์ง€ ์•Š์„ ๋•Œ ๋ฐœ์ƒ



๐Ÿ“ƒ @Enumerated

Enum ํƒ€์ž…์„ ๋งคํ•‘ํ•  ๋•Œ ์‚ฌ์šฉ
์ค‘๊ฐ„์— ๋‹ค๋ฅธ ์ƒํƒœ๊ฐ€ ์ค‘๊ฐ„์— ๋“ค์–ด๊ฐ€๋ฉด ์ˆซ์ž๊ฐ€ ๋ฐ€๋ฆฌ๊ฒŒ ๋˜์–ด ๋งํ•˜๊ฒŒ ๋œ๋‹ค.
์ ˆ๋Œ€ @Enumerated(EnumType.ORDINARY) ์‚ฌ์šฉํ•˜์ง€ ๋ง์ž. ๋ฌด์กฐ๊ฑด STRING์œผ๋กœ


๐Ÿ“ƒ @Temporal

๋‚ ์งœ ํƒ€์ž…์„ ๋งคํ•‘ํ•  ๋•Œ ์‚ฌ์šฉ
ex)TemporalType.DATE -> ๋‚ ์งœ, DB date ํƒ€์ž…๊ณผ ๋งคํ•‘ (2022-08-26)

TemporalType.TIMe -> ์‹œ๊ฐ„, DB time ํƒ€์ž…๊ณผ ๋งคํ•‘ (11:23:12)

TemporalType.TIMESTAMP -> ๋‚ ์งœ์™€ ์‹œ๊ฐ„, DB timestamp ํƒ€์ž…๊ณผ ๋งคํ•‘


๐Ÿ“ƒ Lob

๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค BLOB, CLOB ํƒ€์ž…๊ณผ ๋งคํ•‘
@Lob์—๋Š” ์ง€์ •ํ•  ์ˆ˜ ์žˆ๋Š” ์†์„ฑ์ด ์—†๋‹ค.
๋งคํ•‘ํ•˜๋Š” ํ•„๋“œ ํƒ€์ž…์ด ๋ฌธ์ž๋ฉด CLOB๋งคํ•‘, ๋‚˜๋จธ์ง€๋Š” BLOB ๋งคํ•‘
CLOB: String, char[], java.sql.CLOB
BLOB: byte[], java.sql.BLOB


๐Ÿ“ƒ Transient

ํ•„๋“œ ๋งคํ•‘ํ•˜๊ธฐ ์‹ซ์„ ๋•Œ ์‚ฌ์šฉ
DB์— ์ €์žฅ X, ์กฐํšŒ X
์ฃผ๋กœ ๋ฉ”๋ชจ๋ฆฌ์ƒ์—์„œ๋งŒ ์ž„์‹œ๋กœ ์–ด๋–ค ๊ฐ’์„ ๋ณด๊ด€ํ•˜๊ณ  ์‹ถ์„ ๋•Œ ์‚ฌ์šฉ
@Transient
private Integer temp;

์œ„์— ๊ฒƒ๋“ค์€ ํ•„๋“œ์™€ ์ปฌ๋Ÿผ ๋งคํ•‘์ด์—ˆ์Œ.


๐Ÿ“ƒ DB์‹œํ€€์Šค

๋ช‡ ๊ฐ€์ง€ ์ž‘๋™์„ ์–ด๋–ค ๊ธฐ์ค€์— ๋”ฐ๋ผ ๊ณต๊ฐ„์  ๋˜๋Š” ์‹œ๊ฐ„์ ์œผ๋กœ ์ˆœ์„œ๋ฅผ ์ •ํ•ด ๋†“๋Š” ๊ฒƒ
์ฆ‰ ์˜ค๋ผํด์—์„œ ํ–‰์„ ๊ตฌ๋ถ„ํ•˜๊ธฐ ์œ„ํ•ด์„œ ๊ธฐ๋ณธํ‚ค๋ฅผ ๋‘๋Š”๋ฐ ๊ธฐ ๊ธฐ๋ณธ ํ‚ค๋Š” ์ค‘๋ณต๋œ ๊ฐ’์„ ๊ฐ€์งˆ ์ˆ˜ ์žˆ์œผ๋ฏ€๋กœ ํ•ญ์ƒ ์œ ์ผํ•œ ๊ฐ’์„ ๊ฐ€์ ธ์•ผ ํ•œ๋‹ค.
๊ทธ๋Ÿฐ ๊ธฐ๋ณธ ํ‚ค๊ฐ€ ์œ ์ผํ•œ ๊ฐ’์„ ๊ฐ–๋„๋ก ์‚ฌ์šฉ์ž๊ฐ€ ์ง์ ‘ ์ƒ์„ฑํ•ด๋‚ด๋Š” ๊ฒƒ์ด ์•„๋‹ˆ๋ผ ์ˆซ์ž๋ฅผ ์ž๋™์œผ๋กœ ์ƒ์„ฑํ•ด์ฃผ๋Š” ๋ช…๋ น์–ด๋ฅผ ์˜๋ฏธํ•œ๋‹ค.
(์‹œ์ž‘ ๊ฐ’์ด 1๋ถ€ํ„ฐ ํ•ด์„œ ์ฆ๊ฐ€ํ•˜๋Š” ๊ฐ’ 1๋กœ ์ง„ํ–‰๋œ๋‹ค.)




๊ธฐ๋ณธํ‚ค ๋งคํ•‘

๐Ÿ“ƒ @GeneratedValue

PK๋ฅผ ๋‚˜ํƒ€๋‚ด๊ธฐ ์œ„ํ•ด @Id ์–ด๋…ธํ…Œ์ด์…˜์„ ์‚ฌ์šฉํ•˜๋ฉฐ, ์ƒ์„ฑ ์ „๋žต์„ ์ •์˜ํ•˜๊ธฐ ์œ„ํ•ด @GeneratedValue ๋ฅผ ์‚ฌ์šฉ
๊ธฐ๋ณธํ‚ค๋ฅผ ์ž๋™์œผ๋กœ ์ƒ์„ฑํ•  ๋•Œ์—๋Š” @Id์™€ @GenerratedValue ์–ด๋…ธํ…Œ์ด์…˜์ด ํ•จ๊ป˜ ์‚ฌ์šฉ๋˜์–ด์•ผ ํ•œ๋‹ค.

strategy = GenerationType.Identity
๊ธฐ๋ณธ ํ‚ค ์ƒ์„ฑ์„ DB์— ์œ„์ž„
(DB๊ฐ€ ์•Œ์•„์„œ ํ•ด์ฃผ๋„๋ก)
IDENTITY ์ „๋žต์€ em.persist() ์‹œ์ ์— ์ฆ‰์‹œ INSERT SQL ์‹คํ–‰ ํ•˜๊ณ  DB์—์„œ ์‹๋ณ„์ž๋ฅผ ์กฐํšŒ
์™œ๋ƒํ•˜๋ฉด ์˜์†์„ฑ์€ ์—”ํ‹ฐํ‹ฐ์˜ ์‹๋ณ„๊ฐ’์„ ๊ธฐ์ค€์œผ๋กœ ์—”ํ‹ฐํ‹ฐ๋ฅผ ๊ตฌ๋ณ„ํ•˜๋Š”๋ฐ ํ‚ค๊ฐ’์ด ํ•„์š”ํ•˜๊ธฐ ๋•Œ๋ฌธ

strategy = GenerationType.SEQUENCE
๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์‹œํ€€์Šค๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๊ธฐ๋ณธ ํ‚ค๋ฅผ ํ• ๋‹นํ•œ๋‹ค.
์œ ์ผํ•œ ๊ฐ’์„ ์ˆœ์„œ๋Œ€๋กœ ์ƒ์„ฑํ•˜๋Š” ํŠน๋ณ„ํ•œ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์˜ค๋ธŒ์ ํŠธ ์‚ฌ์šฉ
Data๋ฅผ DB์— Insertํ•œ ํ›„ ๊ธฐ๋ณธ ํ‚ค ๊ฐ’์„ ์กฐํšŒํ•  ์ˆ˜ ์žˆ๋‹ค

ํ…Œ์ด๋ธ”๋งˆ๋‹ค ๋”ฐ๋กœ ์‹œํ€€์Šค๋ฅผ ๊ด€๋ฆฌํ•˜๊ณ  ์‹ถ๋‹ค๋ฉด
@SequenceGenerator() ๋กœ ๋งคํ•‘ํ•œ๋‹ค.

strategy = GenerationType.AUTO
DB ๋ฐฉ์–ธ์— ๋”ฐ๋ผ ์ž๋™ ์ง€์ •

strategy = GenerationType.TABLE
ํ‚ค ์ƒ์„ฑ ์ „์šฉ ํ…Œ์ด๋ธ”์„ ํ•˜๋‚˜ ๋งŒ๋“ค์–ด์„œ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์‹œํ€€์Šค๋ฅผ ํ‰๋‚ด๋‚ด๋Š” ์ „๋žต

๐Ÿ“ƒ ๊ธฐ๋ณธํ‚ค ์ œ์•ฝ์กฐ๊ฑด์€ NULL์ด ์•„๋‹ˆ๊ณ  ์œ ์ผํ•˜๊ณ  ๋ณ€ํ•˜๋ฉด ์•ˆ๋˜๊ธฐ ๋•Œ๋ฌธ์— ๋จผ ๋ฏธ๋ž˜๊นŒ์ง€ ์ด ์กฐ๊ฑด์„ ๋งŒ์กฑํ•˜๋Š” ์ž์—ฐํ‚ค๋Š” ์ฐพ๊ธฐ ์–ด๋ ค์šฐ๋ฏ€๋กœ ๋Œ€๋ฆฌํ‚ค๋ฅผ ์‚ฌ์šฉํ•˜์ž.

๐Ÿ“ƒ Longํ˜• + ๋Œ€์ฒดํ‚ค + ํ‚ค ์ƒ์„ฑ์ „๋žต ์‚ฌ์šฉ

๐Ÿ“ƒ commit

๋ชจ๋“  ์ž‘์—…์„ ์ •์ƒ์ ์œผ๋กœ ์ฒ˜๋ฆฌํ•˜๊ฒ ๋‹ค๊ณ  ํ™•์ •ํ•˜๋Š” ๋ช…๋ น์–ด
commitํ•˜๋ฉด ํ•˜๋‚˜์˜ ํŠธ๋žœ์žญ์…˜ ๊ณผ์ •์„ ์ข…๋ฃŒํ•˜๊ฒŒ ๋œ๋‹ค.
Transaction ์ž‘์—… ๋‚ด์šฉ์„ ์‹ค์ œ DB์— ์ €์žฅํ•˜๊ณ  ์ด์ „ ๋ฐ์ดํ„ฐ๊ฐ€ ์™„์ „ํžˆ UPDATE ๋œ๋‹ค.

๐Ÿ“ƒ rollback

์ž‘์—… ์ค‘ ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ–ˆ์„ ๋•Œ, ํŠธ๋žœ์žญ์…˜์˜ ์ฒ˜๋ฆฌ ๊ณผ์ •์—์„œ ๋ฐœ์ƒํ•œ ๋ณ€๊ฒฝ ์‚ฌํ•ญ์„ ์ทจ์†Œํ•˜๊ณ , ํŠธ๋žœ์žญ์…˜ ๊ณผ์ •์„ ์ข…๋ฃŒ์‹œํ‚จ๋‹ค.
Transaction ์ž‘์—… ๋‚ด์šฉ์„ ์ทจ์†Œํ•˜๊ณ  ์ด์ „ commitํ•œ ๊ณณ๊นŒ์ง€๋งŒ ๋ณต๊ตฌํ•œ๋‹ค.

์—ฐ๊ด€๊ด€๊ณ„ ํŽธ์˜ ๋ฉ”์„œ๋“œ

ํ•œ ๋ฒˆ์— ์–‘๋ฐฉํ–ฅ ๊ด€๊ณ„๋ฅผ ์„ค์ •ํ•˜๋Š” ๋ฉ”์†Œ๋“œ > ์–‘๋ฐฉํ–ฅ์ธ ๊ฒƒ์„ ๊ฐ„๊ฒฐํ•˜๊ฒŒ ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ๋‹ค.
์—ฐ๊ด€๊ด€๊ณ„ ํŽธ์˜ ๋ฉ”์„œ๋“œ์˜ ์œ„์น˜๋Š” ํ•ต์‹ฌ์ ์œผ๋กœ ์ปจํŠธ๋กค ํ•˜๋Š” ์ชฝ์ด ์žˆ๋Š” ๊ฒƒ์ด ์ข‹๋‹ค.
ex) member์™€ order ๊ฐ€ ์–‘๋ฐฉํ–ฅ์ธ๋ฐ ์›๋ž˜๋Š”

public ~~(){
	Member member = new Member();
    Order order = new Order();
    
    member.getOrders().add(order);
    order.setMember(member);
}

์ด๋Ÿฐ ์‹์œผ๋กœ ํ•  ๊ฒƒ์„ ๋‹ค์Œ๊ณผ ๊ฐ™์ด ๊ฐ„๊ฒฐํ•˜๊ฒŒ

public void setMember(Member member) {
        this.member = member;
        member.getOrders().add(this);
    }

@PersistenceContext

์Šคํ”„๋ง์ด ์ƒ์„ฑํ•œ EntityManager๋ฅผ ์ฃผ์ž…ํ•ด์ค€๋‹ค.

@PersistenceContext
private EntityManager em;

@PersistenceUnit

EntityManagerFactory๋ฅผ ์ฃผ์ž…๋ฐ›๊ณ  ์‹ถ๋‹ค๋ฉด

@PersistenceUnit
private EntityManagerFactory emf;





๊ณต๋ถ€ํ•˜๋˜ ๋„์ค‘ localhost:8082 ์ž…๋ ฅ์„ ํ–ˆ๋Š”๋ฐ h2database์— ์—ฐ๊ฒฐํ•˜์ง€ ๋ชปํ•˜๋Š” ์ƒํ™ฉ์ด ๋ฐœ์ƒ.
์ด์ „์— ํ–ˆ์„ ๋•Œ๋Š” ์ž˜ ์‹คํ–‰ ๋๋Š”๋ฐ....

๊ทธ๋ž˜์„œ intellij ์—์„œ JPA Buddy ๋ฅผ ๋‹ค์‹œ restart ํ•˜๊ณ 

<!-- H2 ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค -->
        <dependency>
            <groupId>com.h2database</groupId>
            <artifactId>h2</artifactId>
            <version>1.4.199</version>
        </dependency>

์ œ๋Œ€๋กœ ์ž…๋ ฅํ–ˆ๋Š”์ง€ ํ™•์ธ

๊ทธ๋ฆฌ๊ณ  ์‹คํ–‰ํ•ด๋ดค๋”๋‹ˆ ์—ฐ๊ฒฐ ์ž˜ ๋Œ......






๐Ÿ“– ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ๊ฐœ๋ฐœ

EntityManager : ์—”ํ‹ฐํ‹ฐ๋ฅผ ๊ด€๋ฆฌํ•˜๋Š” ์—ญํ• ์„ ์ˆ˜ํ–‰.
์—”ํ‹ฐํ‹ฐ ๋งค๋‹ˆ์ € ๋‚ด๋ถ€์— ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ(Persistence Context)**๋ผ๋Š” ๊ฑธ ๋‘์–ด์„œ ์—”ํ‹ฐํ‹ฐ๋“ค์„ ๊ด€๋ฆฌ

EntityManagerFactory : ์—”ํ‹ฐํ‹ฐ ๋งค๋‹ˆ์ €(Entity Manager)๋ฅผ ๋งŒ๋“œ๋Š” ๊ณต์žฅ

Persistence.xml์€ JPA๊ฐ€ ์—‘์„ธ์Šคํ•˜๋ ค๋Š” ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค๋“ค์— ๋Œ€ํ•ด ํ•„์š”ํ•œ ์„ค์ •์ •๋ณด ๋“ค์„ ๊ธฐ์ˆ ํ•ด๋‘” ํŒŒ์ผ์ด๋‹ค.


Member

@Entity //JPA๊ฐ€ ๊ด€๋ฆฌํ•  ๊ฐ์ฒด
//@Table(name="user") //์ฟผ๋ฆฌ๊ฐ€ ๋‚˜๊ฐˆ ๋•Œ user๋ผ๋Š” ํ…Œ์ด๋ธ”์— insertํ•˜๋ผ๊ณ  ํ•˜๊ฒŒ ๋จ
public class Member {
    //PK๊ฐ€ ๋ญ”์ง€ ์•Œ๋ ค์คŒ
    @Id
    private Long id;
    private String name;
    //์ƒ์„ฑ์ž๋ฅผ ์ƒ์„ฑํ•˜๋ฉด ์—๋Ÿฌ๊ฐ€ ๋‚˜๋Š” ์ด์œ ๋Š” JPA๋Š” ๊ธฐ๋ณธ์ ์œผ๋กœ ๋‚ด๋ถ€์ ์œผ๋กœ reflection ์ด๋Ÿฐ ๊ฒƒ๋“ค์„
    //์‚ฌ์šฉํ•˜๊ธฐ ๋•Œ๋ฌธ์— ๋™์ ์œผ๋กœ ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•ด์•ผ ํ•œ๋‹ค.

    //๊ทธ๋ž˜์„œ ๊ธฐ๋ณธ์ƒ์„ฑ์ž๋ฅผ ์ƒ์„ฑ

    public Member() {}

    public Member(Long id, String name) {
        this.id = id;
        this.name = name;
    }

    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;
    }
}

JpaMain

public class JpaMain {
    public static void main(String[] args) {
        EntityManagerFactory emf =
                Persistence.createEntityManagerFactory("hello"); //persistence.xml ์—์„œ ์ •ํ•ด๋†“์€ "hello"
        //EntityManagerFactory๋ฅผ ๋งŒ๋“œ๋Š” ์ˆœ๊ฐ„ ๋ฐ์ดํ„ฐ๋ฒ ์ด์„œ์™€ ์—ฐ๊ฒฐ๋„ ๋‹ค ๋˜๊ณ  ์›ฌ๋งŒํ•œ๊ฒŒ ๋‹ค ๋จ
        EntityManager em = emf.createEntityManager();
        //JPA ์—์„œ๋Š” ๊ผญ ํŠธ๋žœ์žญ์…˜์ด๋ผ๋Š” ๋‹จ์œ„๊ฐ€ ๋งค์šฐ ์ค‘์š”ํ•˜๋‹ค.
        //๋ฐ์ดํ„ฐ๋ฅผ ๋ณ€๊ฒฝํ•˜๋Š” ๋ชจ๋“  ์ž‘์—…์€ ๊ผญ ํŠธ๋žœ์žญ์…˜ ์•ˆ์—์„œ ์ž‘์—…์„ ํ•ด์•ผํ•œ๋‹ค.

        EntityTransaction tx = em.getTransaction();
        tx.begin();

        try{
            // ๋“ฑ๋ก
            // Member member = new Member();
            // member.setId(2L);
            // member.setName("HelloB");

            // ์กฐํšŒํ•˜๊ณ  ์‹ถ๋‹ค๋ฉด
            Member findMember = em.find(Member.class, 1L); //๊ฐ์ฒด๋ฅผ ๋Œ€์‹  ์ €์žฅํ•ด์ฃผ๋Š” ๊ฒƒ(์ž๋ฐ” ์ปฌ๋ ‰์…˜์ฒ˜๋Ÿผ ์ƒ๊ฐ)
            System.out.println("findMember.getId() = " + findMember.getId());
            System.out.println("findMember.getName() = " + findMember.getName());

            
            // ์‚ญ์ œ
            // em.remove(findMember) // ์ฐพ์€ ์–˜๋ฅผ ๋„ฃ์–ด์ฃผ๋ฉด ๋œ๋‹ค.
            
            // ์ˆ˜์ •
            findMember.setName("HelloJPA");
            // ์—ฌ๊ธฐ์„œ em.persist()๋กœ ์ €์žฅํ•˜์ง€ ์•Š์•„๋„ ๋œ๋‹ค. -> JPA๋ฅผ ํ†ตํ•ด์„œ Entity๋ฅผ ๊ฐ€์ ธ์˜ค๋ฉด JPA๊ฐ€ ๊ด€๋ฆฌ๋ฅผ ํ•ด์„œ ๋ณ€๊ฒฝ์ด ๋๋Š”์ง€ ์•ˆ ๋๋Š”์ง€ ํŠธ๋žœ์žญ์…˜์„ ์ปค๋ฐ‹ํ•˜๋Š” ์‹œ์ ์— ๋‹ค ์ฒดํฌ๋ฅผ ํ•œ๋‹ค.
            // ๊ทธ๋ž˜์„œ ๋ฐ”๊ผˆ๋‹ค๋ฉด update ์ฟผ๋ฆฌ๋ฅผ ๋‚ ๋ฆฐ๋‹ค.

            tx.commit();
        }catch(Exception e){
            tx.rollback(); //๋ฌธ์ œ๊ฐ€ ์ƒ๊ธฐ๋ฉด ๋กค๋ฐฑ
        }finally{
            em.close();
            //entityManager๊ฐ€ ๊ฒฐ๊ตญ ๋ฐ์ดํ„ฐ ์ปค๋„ฅ์…˜์„ ๋ฌผ๊ณ  ๋™์ž‘ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ๊ผญ ๋‹ซ๋Š”๋‹ค.
        }
        emf.close();
    }
}

์‹คํ–‰ํ–ˆ๋”๋‹ˆ Exception in thread "main" org.hibernate.service.spi.ServiceException: Unable to create requested service [org.hibernate.engine.jdbc.env.spi.JdbcEnvironment]
Caused by: org.hibernate.boot.registry.classloading.spi.ClassLoadingException Unable to load class [org.h2.Driver]

Caused by: java.lang.ClassNotFoundException: Could not load requested class : org.h2.Driver

์—๋Ÿฌ ๋ฐœ์ƒ
ํ•ด๊ฒฐ ->
pom.xml ์ˆ˜์ •

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>jpa-basic</groupId>
    <artifactId>ex1-hello-jpa</artifactId>
    <version>1.0.0</version>
    <dependencies>
        <!-- JPA ํ•˜์ด๋ฒ„๋„ค์ดํŠธ -->
        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-entitymanager</artifactId>
            <version>5.3.10.Final</version>
        </dependency>
        <!-- H2 ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค -->
        <dependency>
            <groupId>com.h2database</groupId>
            <artifactId>h2</artifactId>
            <version>1.4.199</version>
        </dependency>

    </dependencies>
    <properties>
        <maven.compiler.source>11</maven.compiler.source>
        <maven.compiler.target>11</maven.compiler.target>
    </properties>
</project>

๊ทธ๋ฆฌ๊ณ  file -> project structure ์„ ํƒํ•˜๊ณ  Project Settings -> Project์—์„œ SDK ๋ฒ„์ „ํ™•์ธ (11๋กœ ๋ณ€๊ฒฝํ•จ)
Modules ์—์„œ Language Level์„ 11๋กœ ๋ณ€๊ฒฝ (5๋กœ ๋˜์–ด์žˆ์–ด์„œ Error:java: error: release version 5 not supported ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ•จ)
๊ทธ๋ž˜๋„ ์•„์ง ํ•ด๊ฒฐ ์•ˆ๋จ.


H2 Database ์™€ ์—ฐ๊ฒฐ์„ ํ•˜์ง€ ์•Š์€์ œ ๋ฌธ์ œ
๊ทธ๋ž˜์„œ ์ˆจ๊ฒจ์ง„ ์•„์ด์ฝ˜ ์—ด์–ด์„œ H2 DataBase ์—ฐ๊ฒฐํ•˜๋ฉด H2 ์ฝ˜์†” ์ฐฝ์ด ์ƒ๊ธด๋‹ค.
๋‹ค ์ž…๋ ฅํ•˜๊ณ  ์—ฐ๊ฒฐ ์‹œํ—˜ ํ–ˆ๋”๋‹ˆ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค "C:/Users/park/jpashop"์„ ์ฐพ์„ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. ๋ฏธ๋ฆฌ ๋งŒ๋“ค๊ฑฐ๋‚˜ ์›๊ฒฉ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์ƒ์„ฑ์„ ํ—ˆ์šฉ(๋ณด์•ˆ ํ™˜๊ฒฝ์—์„œ๋Š” ๊ถŒ์žฅ๋˜์ง€ ์•Š์Œ) ์ด๋Ÿฐ ์—๋Ÿฌ๊ฐ€ ๋˜ ๋ฐœ์ƒ...... ๋‹ค์‹œ ํ•ด๊ฒฐ ๋ฐฉ์•ˆ ์ฐพ์Œ


ํ•ด๊ฒฐ ์™„๋ฃŒ
์ƒˆ๋กœ์šด DataBase ๋ฅผ ์ƒ์„ฑํ•  ๋•Œ๋Š” ์•„์ด์ฝ˜์„ ์˜ค๋ฅธ์ชฝ ๋ฒ„ํŠผ ํด๋ฆญํ•ด์„œ create new DataBase๋กœ ์ƒ์„ฑํ•œ๋‹ค. ๊ทธ๋Ÿฌ๋ฉด
์š”๋Ÿฐ ์ฐฝ์ด ๋œจ๋Š”๋ฐ Database Path๋ฅผ ์ž„์˜๋กœ ๋ฐ”๊พธ๊ณ  ๋น„๋ฐ€๋ฒˆํ˜ธ๋Š” ์•„๋ฌด๊ฑฐ๋‚˜ ์ณ๋„ ์ƒ๊ด€์—†์Œ.
๊ทธ๋ฆฌ๊ณ ๋‚˜์„œ ๋‹ค์‹œ H2 ์ฝ˜์†”๋กœ ๊ฐ€์„œ JDBC URL์— jdbc:h2:./jpashop ๋ฅผ ์ž…๋ ฅํ•˜๊ณ  ๋น„๋ฐ€๋ฒˆํ˜ธ ์ž…๋ ฅํ•˜๋ฉด ์—ฐ๊ฒฐ ์™„๋ฃŒ๋Œ.

์—ฌ๊ธฐ๋„ ์ˆ˜์ •

H2 ์ฝ˜์†”์€ ํ•ด๊ฒฐ ๋๋Š”๋ฐ ๋˜ Intellij์—์„œ File corrupted while reading record ์—๋Ÿฌ ๋ฐœ์ƒ
ํ•ด๊ฒฐ -> Intellij ์—์„œ jpashop.mv.db ์™€ jpashop.trace.db ์‚ญ์ œ ํ›„ ๋‹ค์‹œ ์‹คํ–‰

์ž๊พธ ์‹คํ–‰๋๋‹ค ์•ˆ๋๋‹ค ํ•˜๋Š”๊ฒŒ ๋ถˆํŽธํ–ˆ์—ˆ๋‹ค...... ์ด์ œ ํ•ด๊ฒฐ๋๋‹ค... (๋„ˆ๋ฌด ์˜ค๋ž˜ ๊ฑธ๋ ธ๋‹ค....)




๋ฉค๋ฒ„๋ฅผ ์ €์žฅํ•˜๋Š” ๋ฐฉ๋ฒ•
EntityManagerFactory๋ฅผ Application ๋กœ๋”ฉ ์‹œ์ ์— ๋”ฑ ํ•˜๋‚˜๋งŒ ๋งŒ๋“ ๋‹ค.
์‹ค์ œ DB์— ์ €์žฅํ•˜๋Š” ๊ฒƒ์€ ํŠธ๋žœ์žญ์…˜ ๋‹จ์œ„๋กœ DB ์ปค๋„ฅ์…˜์„ ์–ป์–ด์„œ ์ฟผ๋ฆฌ๋ฅผ ๋‚ ๋ฆฌ๊ณ  ์ข…๋ฃŒ๋˜๋Š” ์ผ๊ด€์ ์ธ ๋‹จ์œ„๋ฅผ ํ•  ๋•Œ๋งˆ๋‹ค EntityManager๋ผ๋Š” ๊ฒƒ์„ ๋งŒ๋“ค์–ด ์ค˜์•ผ ํ•œ๋‹ค.



๐Ÿ’— ๋งค์šฐ ์ค‘์š”

1) EntityManagerFactory๋Š” ํ•˜๋‚˜๋งŒ ์ƒ์„ฑํ•ด์„œ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์ „์ฒด์—์„œ ๊ณต์œ 
2) EntityManager๋Š” ์“ฐ๋ ˆ๋“œ๊ฐ„์— ๊ณต์œ X(์‚ฌ์šฉํ•˜๊ณ  ๋ฒ„๋ ค์•ผ ํ•œ๋‹ค.)
3) JPA์˜ ๋ชจ๋“  ๋ฐ์ดํ„ฐ ๋ณ€๊ฒฝ์€ ํŠธ๋žœ์žญ์…˜ ์•ˆ์—์„œ ์‹คํ–‰ํ•ด์•ผ ํ•œ๋‹ค.






๐Ÿช” JPQL ๊ฐ„๋‹จ ์†Œ๊ฐœ

JPQL๋กœ ์ „์ฒด ํšŒ์› ๊ฒ€์ƒ‰ํ•˜๊ณ  ์‹ถ๋‹ค๋ฉด try{} ์—๋‹ค๊ฐ€ ์ฝ”๋“œ ์ž‘์„ฑ.

//JPQL๋กœ ์ „์ฒด ํšŒ์› ๊ฒ€์ƒ‰ํ•˜๊ณ  ์‹ถ๋‹ค๋ฉด
List<Member> result = em.createQuery("select m from Member as m", Member.class)
         .getResultList();
//JPA๋Š” ์ ˆ๋Œ€ ํ…Œ์ด๋ธ”์„ ๋Œ€์ƒ์œผ๋กœ ์ฝ”๋“œ๋ฅผ ์งœ์ง€ ์•Š๋Š”๋‹ค. Member ๊ฐ์ฒด๋ฅผ ๋Œ€์ƒ์œผ๋กœ ํ•œ๋‹ค.

for (Member member : result) {
	System.out.println("member.getName() = " + member.getName());
}

JPA๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์—”ํ‹ฐํ‹ฐ ๊ฐ์ฒด๋ฅผ ์ค‘์‹ฌ์œผ๋กœ ๊ฐœ๋ฐœํ•˜๋Š”๋ฐ ๋ฌธ์ œ๋Š” ๊ฒ€์ƒ‰ ์ฟผ๋ฆฌ์ด๋‹ค. ๊ฒ€์ƒ‰์„ ํ•  ๋•Œ๋„ ํ…Œ์ด๋ธ”์ด ์•„๋‹Œ ๊ฐ์ฒด๋ฅผ ๋Œ€์ƒ์œผ๋กœ ๊ฒ€์ƒ‰์„ ํ•ด๋ฒ„๋ฆฐ๋‹ค.

  • ๋ชจ๋“  DB ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ์ฒด๋กœ ๋ณ€ํ™˜ํ•ด์„œ ๊ฒ€์ƒ‰ํ•˜๋Š” ๊ฒƒ์€ ๋ถˆ๊ฐ€๋Šฅ.

  • ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์ด ํ•„์š”ํ•œ ๋ฐ์ดํ„ฐ๋งŒ DB์—์„œ ๋ถˆ๋Ÿฌ์˜ค๋ ค๋ฉด ๊ฒฐ๊ตญ ๊ฒ€์ƒ‰ ์กฐ๊ฑด์ด ํฌํ•จ๋œ SQL์ด ํ•„์š”.


JPQL

  1. JPA๋Š” SQL์„ ์ถ”์ƒํ™”ํ•œ JPQL์ด๋ผ๋Š” ๊ฐ์ฒด ์ง€ํ–ฅ ์ฟผ๋ฆฌ ์–ธ์–ด๋ฅผ ์ œ๊ณต.
  2. ์—”ํ‹ฐํ‹ฐ ๊ฐ์ฒด๋ฅผ ๋Œ€์ƒ์œผ๋กœ ์ฟผ๋ฆฌ.
  3. SQL์€ DB ํ…Œ์ด๋ธ”์„ ๋Œ€์ƒ์œผ๋กœ ์ฟผ๋ฆฌ.



public static void main(String[] args) {
	EntityManagerFactory emf =
	Persistence.createEntityManagerFactory("hello"); //persistence.xml ์—์„œ ์ •ํ•ด๋†“์€ "hello"

    EntityManager em = emf.createEntityManager();

    EntityTransaction tx = em.getTransaction();
    tx.begin();

    try{
    	Member member = new Member();
        member.setId(101L);
        member.setName("HelloJPA");
        //์—ฌ๊ธฐ๊นŒ์ง€๋Š” ๋น„์˜์†

		//em.persist(member); //์—ฌ๊ธฐ๋ถ€ํ„ฐ ์˜์†์ƒํƒœ๊ฐ€ ๋จ, DB์— ์ €์žฅ์ด ๋˜์ง€๋Š” ์•Š์Œ
		// EntityManager ์•ˆ์— ์žˆ๋Š” ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ๋ผ๋Š” ๋ฐ๋ฅผ ํ†ตํ•ด์„œ member๊ฐ€ ๊ด€๋ฆฌ๋œ๋‹ค๋Š” ๋œป

		System.out.println("BEFORE");
        em.persist(member);
        System.out.println("AFTER");
            //em.detach(member);
            //ํšŒ์› ์—”ํ‹ฐํ‹ฐ๋ฅผ ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ์—์„œ ๋ถ„๋ฆฌ (์ค€์˜์† ์ƒํƒœ)

        //์กฐํšŒ
        Member findMember1 = em.find(Member.class, 101L);
        Member findMember2 = em.find(Member.class, 101L);

		System.out.println("result = " + (findMember1 == findMember2));
            // ๊ฒฐ๊ณผ๋Š” true๊ฐ€ ๋‚˜์˜จ๋‹ค.
            //์˜์† ์—”ํ‹ฐํ‹ฐ์˜ ๋™์ผ์„ฑ์„ ๋ณด์žฅํ•ด์ฃผ๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.
        tx.commit();
    }
    
    catch(Exception e){
        tx.rollback();
    }
    
    finally{
        em.close();
    }
    
    emf.close();

EntityManagerFactory emf =
     	Persistence.createEntityManagerFactory("hello"); //persistence.xml ์—์„œ ์ •ํ•ด๋†“์€ "hello"

        EntityManager em = emf.createEntityManager();

        EntityTransaction tx = em.getTransaction();
        tx.begin();

        try{
            Member member1 = new Member(150L, "A");
            Member member2 = new Member(151L, "B");

            em.persist(member1);
            em.persist(member2);
            //์ด ์ˆœ๊ฐ„์— DB์— ์ €์žฅ๋˜๋Š” ๊ฒƒ์ด ์•„๋‹ˆ๋ผ ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ์— ์ฐจ๊ณก์ฐจ๊ณก ์—”ํ‹ฐํ‹ฐ์™€ ์ฟผ๋ฆฌ๊ฐ€ ์Œ“์ธ๋‹ค.
            tx.commit(); //์—ฌ๊ธฐ ์ปค๋ฐ‹์„ ํ•˜๋Š” ์‹œ์ ์— ์ง„์งœ DB์— ์ฟผ๋ฆฌ๊ฐ€ ๋‚ ๋ผ๊ฐ
            System.out.println("===================");

            //๋ฒ„ํผ๋ง์ด๋ผ๋Š” ๊ธฐ๋Šฅ์ด ์žˆ๋‹ค. ์œ„์ฒ˜๋Ÿผ ์ฟผ๋ฆฌ๋ฅผ DB์— ๋‚ ๋ฆฌ๋ฉด ์ตœ์ ํ™”์˜ ์—ฌ์ง€๊ฐ€ ์—†๋‹ค.
            //member1,2 ๊ฐ€ ์Œ“์˜€๋Š”๋ฐ ์ด๊ฒƒ๋“ค์„ DB์— ํ•œ ๋ฒˆ์— ๋ณด๋‚ผ ์ˆ˜ ์žˆ๋‹ค.
            //hibernate์— batch_size๊ฐ€ ์žˆ๋Š”๋ฐ ์ด๊ฒƒ์€ size ๋งŒํผ ๋ชจ์•„์„œ DB์— ํ•œ ๋ฐฉ์— ๋„คํŠธ์›Œํฌ๋กœ ์ฟผ๋ฆฌ 2๊ฐœ๋ฅผ ๋ณด๋‚ด๊ณ  DB๋ฅผ commitํ•œ๋‹ค.
        }catch(Exception e){
            tx.rollback();
        }finally{
            em.close();
        }
        emf.close();

์Šค๋ƒ…์ƒท: ํ–ฅํ›„ ๋ณ€๊ฒฝ ๊ฐ์ง€๋ฅผ ์œ„ํ•ด์„œ ์›๋ณธ์„ ๋ณต์‚ฌํ•ด์„œ ๋งŒ๋“ค์–ด๋‘๋Š” ๊ฐ์ฒด๊ฐ€ ๋ฐ”๋กœ ์Šค๋ƒ…์ƒท์ด๋‹ค. ๋ณ€๊ฒฝ ๊ฐ์ง€๊ฐ€ ์ผ์–ด๋‚ฌ์„ ๋•Œ 1์ฐจ์บ์‹œ์— ์žˆ๋Š” ์›๋ณธ ๊ฐ์ฒด๊ฐ€ ์ค‘๊ฐ„์— ๋ณ€๊ฒฝ๋˜์—ˆ๋Š”์ง€ ์ด ์Šค๋ƒ…์ƒท์œผ๋กœ ํ™•์ธํ•˜๊ฒŒ ๋œ๋‹ค.


try{
      //์—”ํ‹ฐํ‹ฐ ์ˆ˜์ •
      /*Member member = em.find(Member.class, 150);
      member.setName("ZZZZZ");
      em.persist(member);  ์“ฐ์ง€ ์•Š๋„๋ก ํ•œ๋‹ค.
      ์ปฌ๋ ‰์…˜์— ๋„ฃ์€ ๊ฒƒ์ฒ˜๋Ÿผ ๊ฐ’์„ ๊บผ๋‚ด๊ณ  ๋ณ€๊ฒฝํ–ˆ๋Š”๋ฐ ๋‹ค์‹œ ์ปฌ๋ ‰์…˜์— ๋„ฃ์„ ํ•„์š”๊ฐ€ ์—†๋‹ค.*/

      Member member = new Member(200L, "member200");
      em.persist(member);
      //๋ฉค๋ฒ„๋ฅผ ์ €์žฅํ–ˆ๋Š”๋ฐ ์ปค๋ฐ‹๋˜๊ธฐ ์ „๊นŒ์ง€๋Š” ์ฟผ๋ฆฌ๋ฅผ ๋ณผ ์ˆ˜๊ฐ€ ์—†๋‹ค.
      //๋ฏธ๋ฆฌ DB์— ๋ฐ˜์˜ํ•˜๊ณ  ์‹ถ๋‹ค๊ฑฐ๋‚˜ ์ฟผ๋ฆฌ๋ฅผ ๋ฏธ๋ฆฌ ๋ณด๊ณ  ์‹ถ๋‹ค๋ฉด
      
      em.flush(); //๋ฅผ ๊ฐ•์ œ๋กœ ํ˜ธ์ถœํ•œ๋‹ค. flush ํ•ด๋„ 1์ฐจ ์บ์‹œ๋Š” ์ง€์›Œ์ง€์ง€ ์•Š์Œ

      System.out.println("==============");
     //๊ทธ๋Ÿฌ๋ฉด update ์ปค๋ฆฌ๋„ ๋‚˜์˜จ๋‹ค.
 }
 catch(Exception e){
      tx.rollback();
 }
 finally{
     em.close();
}

emf.close();





๐Ÿ“– ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ

โ— ์—”ํ‹ฐํ‹ฐ๋ฅผ ์˜๊ตฌ ์ €์žฅํ•˜๋Š” ํ™˜๊ฒฝ์ด๋‹ค.
โ— ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜๊ณผ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์‚ฌ์ด์—์„œ ๊ฐ์ฒด๋ฅผ ๋ณด๊ด€ํ•˜๋Š” ๊ฐ€์ƒ์˜ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ๊ฐ™์€ ์—ญํ• ์„ ํ•œ๋‹ค.
โ— ์—”ํ‹ฐํ‹ฐ ๋งค๋‹ˆ์ €๋ฅผ ํ†ตํ•ด ์—”ํ‹ฐํ‹ฐ๋ฅผ ์ €์žฅํ•˜๊ฑฐ๋‚˜ ์กฐํšŒํ•˜๋ฉด ์—”ํ‹ฐํ‹ฐ ๋งค๋‹ˆ์ €๋Š” ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ์— ์—”ํ‹ฐํ‹ฐ๋ฅผ ๋ณด๊ด€ํ•˜๊ณ  ๊ด€๋ฆฌํ•œ๋‹ค

๋น„์˜์†(new/transient): ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ์™€ ์ „ํ˜€ ๊ด€๊ณ„๊ฐ€ ์—†๋Š” ์ƒํƒœ ์˜์†(managed): ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ์— ์ €์žฅ๋œ ์ƒํƒœ ์ค€์˜์†(detached): ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ์— ์ €์žฅ๋˜์—ˆ๋‹ค๊ฐ€ ๋ถ„๋ฆฌ๋œ ์ƒํƒœ ์‚ญ์ œ(removed): ์‚ญ์ œ๋œ ์ƒํƒœ

์žฅ์  : 1์ฐจ ์บ์‹œ, ๋™์ผ์„ฑ ๋ณด์žฅ, ํŠธ๋žœ์žญ์…˜์„ ์ง€์›ํ•˜๋Š” ์“ฐ๊ธฐ ์ง€์—ฐ, ๋ณ€๊ฒฝ ๊ฐ์ง€, ์ง€์—ฐ ๋กœ๋”ฉ

1์ฐจ ์บ์‹œ
๋™์ผํ•œ ํŠธ๋žœ์žญ์…˜ ๋‚ด์—์„œ ํ•œ๋ฒˆ ์กฐํšŒํ–ˆ๋˜๊ฑฐ ๋˜ ์กฐํšŒํ•˜๋ฉด DB์— ์ฟผ๋ฆฌ ๋‚ ๋ผ๊ฐ€์ง€ ์•Š์Œ






๐Ÿ“– ํ”Œ๋Ÿฌ์‹œ

flush() : ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ์˜ ๋ณ€๊ฒฝ๋‚ด์šฉ์„ DB์— ๋ฐ˜์˜
flush ๋ฐœ์ƒํ•˜๋ฉด ๋ณ€๊ฒฝ์„ ๊ฐ์ง€ํ•˜๊ณ  ์ˆ˜์ •๋œ ์—”ํ‹ฐํ‹ฐ ์“ฐ๊ธฐ ์ง€์—ฐ SQL ์ €์žฅ์†Œ์— ๋“ฑ๋กํ•˜๊ณ  ์“ฐ๊ธฐ ์ง€์—ฐ SQL ์ €์žฅ์†Œ์˜ ์ฟผ๋ฆฌ๋ฅผ DB์— ์ „์†กํ•œ๋‹ค. (SQL ์ €์žฅ์†Œ์—๋Š” ๋“ฑ๋ก, ์ˆ˜์ •, ์‚ญ์ œ ์ฟผ๋ฆฌ๊ฐ€ ๋‹ด๊ฒจ์žˆ๋‹ค.)
ํ”Œ๋Ÿฌ์‹œ๋Š” ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ๋ฅผ ๋น„์šฐ๋Š” ๊ฒƒ์ด ์•„๋‹ˆ๋‹ค.
์ปจํ…์ŠคํŠธ์˜ ๋ณ€๊ฒฝ ๋‚ด์šฉ์„ DB์— ๋™๊ธฐํ™”ํ•œ๋‹ค๊ณ  ์ดํ•ด.
ํŠธ๋žœ์žญ์…˜์ด๋ผ๋Š” ์ž‘์—… ๋‹จ์œ„๊ฐ€ ์ค‘์š” -> ์ปค๋ฐ‹ ์ง์ „์—๋งŒ ๋™๊ธฐํ™”

์–ด๋–ป๊ฒŒ๋“  ์ปค๋ฐ‹ ์ง์ „์—๋งŒ ๋ณ€๊ฒฝ ๋‚ด์šฉ์„ DB์— ๋‚ ๋ ค์ฃผ๋ฉด ๋œ๋‹ค.



em.persist(member)
์ด๊ฑฐ ํ•  ๋•Œ ์‹ค์ œ๋กœ DB์— ์ฟผ๋ฆฌ๊ฐ€ ๋‚ ๋ผ๊ฐ€์ง€๋Š” ์•Š๋Š”๋‹ค.
์ฆ‰ ์˜์†์„ฑ ์ƒํƒœ๊ฐ€ ๋œ๋‹ค๊ณ  ํ•ด์„œ ๋ฐ”๋กœ DB์— ์ฟผ๋ฆฌ๊ฐ€ ๋‚ ๋ผ๊ฐ€๋Š” ๊ฒƒ์€ ์•„๋‹ˆ๋‹ค. ํŠธ๋žœ์žญ์…˜์„ ์ปค๋ฐ‹ํ•˜๋Š” ์‹œ์ ์— ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ์— ์žˆ๋Š” ์ฟผ๋ฆฌ๊ฐ€ DB๋กœ ๋‚ ๋ผ๊ฐ„๋‹ค.






๐Ÿ“– ์ค€์˜์† ์ƒํƒœ

em.find() ๋กœ member2๋ฅผ ์กฐํšŒํ–ˆ๋Š”๋ฐ 1์ฐจ ์บ์‹œ์— ์—†๋‹ค๋ฉด DB์—์„œ ๊ฐ€์ ธ์™€์„œ 1์ฐจ ์บ์‹œ์— ์˜ฌ๋ฆฐ๋‹ค. ์ด ๋•Œ ์˜ฌ๋ผ๊ฐ„ ์ƒํƒœ๊ฐ€ ์˜์† ์ƒํƒœ์ด๋‹ค.

์ค€์˜์† ์ƒํƒœ๋Š” ์˜์† ์ƒํƒœ์˜ ์—”ํ‹ฐํ‹ฐ๊ฐ€ ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ์—์„œ ๋ถ„๋ฆฌ๋˜๋Š” ๊ฒƒ์ด๋‹ค. ๊ทธ๋Ÿฌ๋ฉด ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ๊ฐ€ ์ œ๊ณตํ•˜๋Š” ๊ธฐ๋Šฅ์„ ์‚ฌ์šฉํ•˜์ง€ ๋ชปํ•œ๋‹ค.

EntityManagerFactory emf = Persistence.createEntityManagerFactory("hello"); //persistence.xml ์—์„œ ์ •ํ•ด๋†“์€ "hello"

    EntityManager em = emf.createEntityManager();

    EntityTransaction tx = em.getTransaction();
    tx.begin();

    try{
    	Member member = em.find(Member.class, 150L);
        member.setName("AAAA");
            //์กฐํšŒํ–ˆ๋”๋‹ˆ 150L์ด ์—†์œผ๋ฏ€๋กœ ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ์— 150L์„ ์˜ฌ๋ฆฐ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ๊ฐ’์„ "AAAA"๋กœ ๋ณ€๊ฒฝ

            //๋” ์ด์ƒ ์˜์†์„ฑ ๊ด€๋ฆฌ๋ฅผ ํ•˜๊ธฐ ์‹ซ๋‹ค๋ฉด
        em.detach(member); //๋ถ„๋ฆฌ -> JPA์—์„œ ๋” ์ด์ƒ ๊ด€๋ฆฌ๋ฅผ ํ•˜์ง€ ์•Š์Œ
            //๊ทธ๋Ÿฌ๋ฉด ํŠธ๋žœ์žญ์…˜ commitํ•  ๋•Œ ์•„๋ฌด ์ผ๋„ ์ผ์–ด๋‚˜์ง€ ์•Š์Œ
    }
    catch(Exception e){
       tx.rollback();
    }
    finally{
       em.close();
    }
emf.close();

em.detach(entity)
ํŠน์ • ์—”ํ‹ฐํ‹ฐ๋งŒ ์ค€์˜์† ์ƒํƒœ๋กœ ์ „ํ™˜

em.clear()
์˜์†์„ฑ ์ปจํ…์ŠคํŠธ๋ฅผ ํ†ต์งธ๋กœ ์ง€์›Œ๋ฒ„๋ฆผ (์ดˆ๊ธฐํ™”)

em.close()
์˜์†์„ฑ ์ปจํ…์ŠคํŠธ๋ฅผ ์ข…๋ฃŒ

FlushModeType.AUTO
์ปค๋ฐ‹์ด๋‚˜ ์ฟผ๋ฆฌ๋ฅผ ์‹คํ–‰ํ•  ๋•Œ ํ”Œ๋Ÿฌ์‹œํ•œ๋‹ค.
(AUTO ๋งŒ ์‚ฌ์šฉํ•œ๋‹ค๊ณ  ์ดํ•ด)






๐Ÿ“– ๋ณ€๊ฒฝ ๊ฐ์ง€(๋”ํ‹ฐ ์ฒดํ‚น)

๋ฐ์ดํ„ฐ๋ฅผ ์ˆ˜์ •ํ•ด์„œ Transaction์—์„œ ์ปค๋ฐ‹ํ•˜๋ฉด JPA๊ฐ€ ๋ณ€๊ฒฝ๋ถ„์— ๋Œ€ํ•ด์„œ ์ฐพ์•„์„œ ์ž๋™์œผ๋กœ update ์ฟผ๋ฆฌ๋ฅผ ์ƒ์„ฑํ•ด์„œ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์— ๋ฐ˜์˜ํ•œ๋‹ค.
JPA์˜ ์—”ํ‹ฐํ‹ฐ๋ฅผ ๋ฐ”๊ฟ€ ์ˆ˜ ์žˆ๋‹ค.



๐Ÿท๏ธ ์ค€์˜์† ์—”ํ‹ฐํ‹ฐ

์˜์†์„ฑ ์ปจํ…์ŠคํŠธ๊ฐ€ ๋”๋Š” ๊ด€๋ฆฌํ•˜์ง€ ์•Š๋Š” ์—”ํ‹ฐํ‹ฐ

@PostMapping("items/{itemId}/edit")
//ํŒŒ๋ผ๋ฏธํ„ฐ๋กœ ๋„˜์–ด์˜จ ์ค€์˜์† ์ƒํƒœ์˜ ์—”ํ‹ฐํ‹ฐ.
public String updateItem(@PathVariable Long itemId, @ModelAttribute("form") BookForm form) {
    Book book = new Book();
    book.setId(form.getId()); //form์„ book์œผ๋กœ ๋ฐ”๊ฟˆ
    book.setName(form.getName());
    book.setPrice(form.getPrice());
    book.setStockQuantity(form.getStockQuantity());
    book.setAuthor(form.getAuthor());
    book.setIsbn(form.getIsbn());

	//์–ด์„คํ”„๊ฒŒ ์—”ํ‹ฐํ‹ฐ๋ฅผ ํŒŒ๋ผ๋ฏธํ„ฐ๋กœ ์•ˆ ์“ฐ๊ณ  ์ •ํ™•ํ•˜๊ฒŒ ํ•„์š”ํ•œ ๋ฐ์ดํ„ฐ๋งŒ ๋ฐ›์Œ
	itemService.saveItem(book);
	return "redirect:items";
}

์—ฌ๊ธฐ์„œ ๊ฐ์ฒด๋Š” ์ƒˆ๋กœ์šด ๊ฐ์ฒด์ง€๋งŒ Id๊ฐ€ ์„ธํŒ…๋˜์–ด์žˆ์œผ๋ฏ€๋กœ ๋ญ”๊ฐ€ JPA์— ๋“ค์–ด๊ฐ”๋‹ค ๋‚˜์˜จ ๊ฒƒ์ด๋ผ๋Š” ์˜๋ฏธ์ด๋‹ค. ๊ทธ๋ž˜์„œ DB์— ์ •ํ™•ํžˆ ๊ฐ”๋‹ค ์˜จ ์ƒํƒœ(ํ•œ ๋ฒˆ ์ €์žฅ๋œ ์ƒํƒœ)๋กœ ์‹๋ณ„์ž๊ฐ€ DB์— ์žˆ์œผ๋ฉด ์ค€์˜์† ์ƒํƒœ์˜ ๊ฐ์ฒด๋ผ ํ•œ๋‹ค.

  • new ๋กœ Book ์ƒˆ๋กœ์šด ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•˜๊ธฐ๋Š” ํ–ˆ์ง€๋งŒ JPA์—์„œ Id ๊ธฐ๋ฐ˜์œผ๋กœ ์ƒ๊ฐ์„ ํ•ด๋ณด๋ฉด
    ์ด๋ฏธ DB์— ํ•œ๋ฒˆ ์ €์žฅ๋˜๊ณ  ๋ถˆ๋Ÿฌ์˜จ ๊ฒƒ์ด๋‹ค.
  • ๋”ฐ๋ผ์„œ ์ค€์˜์† ์—”ํ‹ฐํ‹ฐ๋ผ๊ณ  ๋ณด๋Š” ๊ฒƒ์ด ๋งž๋‹ค.
    Book์ด ์ค€์˜์† ์—”ํ‹ฐํ‹ฐ (์ด๋ฏธ DB์— ํ•œ๋ฒˆ ์ €์žฅ๋ผ์„œ ์‹๋ณ„์ž๊ฐ€ ์กด์žฌํ•˜๋ฉด ์ค€์˜์† ์—”ํ‹ฐํ‹ฐ๋ผ ๋ณผ ์ˆ˜ ์žˆ๋‹ค.)
  • ์œ„ ์˜ˆ์‹œ์ฒ˜๋Ÿผ ๊ทธ๋ƒฅ new๋กœ ์ง์ ‘ ๋งŒ๋“  ๊ฒƒ์€ ๊ธฐ๋ณธ์ ์œผ๋กœ JPA๊ฐ€ ๊ด€๋ฆฌํ•˜์ง€ ์•Š๋Š”๋‹ค. ๊ทธ๋ž˜์„œ ์•„๋ฌด๋ฆฌ ๋ฐ”๊ฟ”์น˜๊ธฐ ํ•ด๋„ DB์— ์—…๋ฐ์ดํŠธ๊ฐ€ ๋˜์ง€ ์•Š๋Š”๋‹ค.

์˜์†์„ฑ ์—”ํ‹ฐํ‹ฐ๋Š” JPA๊ฐ€ ๊ด€๋ฆฌํ•ด์„œ ๋ณ€๊ฒฝ๊ฐ์ง€๊ฐ€ ์ผ์–ด๋‚œ๋‹ค. ์ค€์˜์† ์ƒํƒœ์˜ ์—”ํ‹ฐํ‹ฐ๋Š” JPA๊ฐ€ ๊ด€๋ฆฌํ•˜์ง€ ์•Š๋Š”๋‹ค.
๐Ÿ’ง ๊ทธ๋ž˜์„œ ์ค€์˜์† ์ƒํƒœ ์—”ํ‹ฐํ‹ฐ์ง€๋งŒ ๋ณ€๊ฒฝ ๊ฐ์ง€ ๊ธฐ๋Šฅ์„ ์‚ฌ์šฉํ•˜๊ฑฐ๋‚˜ ๋ณ‘ํ•ฉ(merge)์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

//์ค€์˜์†์„ฑ ์ƒํƒœ Book์„ ๋ณ€๊ฒฝ ๊ฐ์ง€
@Transactional
public void updateItem(Long itemId, Book param){
    //itemId๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœ ์‹ค์ œ DB์— ์žˆ๋Š” ์˜์†์„ฑ ์—”ํ‹ฐํ‹ฐ๋ฅผ ์ฐพ์•„์˜ด
    Item findItem = itemRepository.findOne(itemId);
    findItem.setPrice(param.getPrice());
    findItem.setName(param.getName());
    findItem.setStockQuantity(param.getStockQuantity());
    //save ํ˜ธ์ถœ๋„ ํ•„์š”์—†์Œ. persist ํ˜ธ์ถœ๋„ ํ•„์š”์—†์Œ
    // ์ด ๋ผ์ธ์ด ๋๋‚˜๋ฉด ์Šคํ”„๋ง์˜ ํŠธ๋žœ์žญ์…˜์— ์˜ํ•ด์„œ ํŠธ๋žœ์žญ์…˜์ด ์ปค๋ฐ‹๋œ๋‹ค.
}

findItem์€ ์˜์† ์ƒํƒœ์ด๋‹ค.
๊ฐ’์„ ์„ธํŒ…ํ•œ ๋‹ค์Œ์—๋Š” ์Šคํ”„๋ง์˜ @Transactional์— ์˜ํ•ด ์ปค๋ฐ‹๋œ๋‹ค.
์ปค๋ฐ‹๋˜๋ฉด JPA๋Š” flush๋ฅผ ํ•œ๋‹ค. ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ์— ์žˆ๋Š” ์—”ํ‹ฐํ‹ฐ ์ค‘์—์„œ ๋ณ€๊ฒฝ๋œ ๊ฒƒ๋“ค์„ ๋‹ค ์ฐพ๋Š”๋‹ค.
๋ฐ”๋€Œ์—ˆ๋‹ค๋ฉด ๋ฐ”๋€ ๊ฒƒ์— ๋Œ€ํ•ด์„œ update ์ฟผ๋ฆฌ๋ฅผ DB์— ๋‚ ๋ ค์„œ updateํ•œ๋‹ค.





๐Ÿ““ merge

์ค€์˜์† ์ƒํƒœ์˜ ์—”ํ‹ฐํ‹ธ๋ฅผ ์˜์† ์ƒํƒœ๋กœ ๋ณ€๊ฒฝํ•  ๋•Œ ์‚ฌ์šฉํ•˜๋Š” ๊ธฐ๋Šฅ์ด๋‹ค.

  • ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ์—์„œ findItemId๋กœ ์ฐพ์€ Id๋กœ DB๋ฅผ ๋’ค์ ธ์„œ Item์„ ์ฐพ๊ณ  ํŒŒ๋ผ๋ฏธํ„ฐitem ๊ฐ’์œผ๋กœ ์ฐพ์•„์˜จ ๊ฐ’๋“ค์„ ์ „๋ถ€ ๋ฐ”๊ฟ”์น˜๊ธฐ ํ•œ๋‹ค.
  • ๊ทธ๋ž˜์„œ ํŠธ๋žœ์žญ์…˜ ์ปค๋ฐ‹๋  ๋•Œ ๋ฐ˜์˜์ด ๋œ๋‹ค.
public void save(Item item) {
  if (item.getId() == null) { //item์€ JPA์— ๋ฐ์ดํ„ฐ ์ €์žฅ ์ „๊นŒ์ง€ Id๊ฐ€ ์—†๋‹ค.
      em.persist(item);
  }//๊ทธ๋ž˜์„œ JPA๊ฐ€ ์ œ๊ณตํ•˜๋Š” persist๋ฅผ ์‚ฌ์šฉ

  else{ //์ด๋ฏธ DB์— ๋“ฑ๋ก๋ผ์„œ ๊ฐ€์ ธ์˜จ ๊ฒƒ
      em.merge(item);
  }
}

๐Ÿท๏ธ ๋™์ž‘ ๋ฐฉ์‹

  1. merge() ์‹คํ–‰
  2. ํŒŒ๋ผ๋ฏธํ„ฐ๋กœ ๋„˜์–ด์˜จ ์ค€์˜์† ์—”ํ‹ฐํ‹ฐ์˜ ์‹๋ณ„์ž ๊ฐ’์œผ๋กœ 1์ฐจ ์บ์‹œ์—์„œ ์—”ํ‹ฐํ‹ฐ๋ฅผ ์กฐํšŒ
    -> ์—†์œผ๋ฉด DB์—์„œ ์—”ํ‹ฐํ‹ฐ๋ฅผ ์กฐํšŒํ•˜๊ณ  1์ฐจ ์บ์‹œ์— ์ €์žฅ
  3. ์กฐํšŒํ•œ ์˜์†์„ฑ ์—”ํ‹ฐํ‹ฐ์— ํŒŒ๋ผ๋ฏธํ„ฐ๋กœ ๋„˜์–ด์˜จ ์ค€์˜์† ์ƒํƒœ ์—”ํ‹ฐํ‹ฐ์˜ ๊ฐ’์„ ์ฑ„์›Œ ๋†“๋Š”๋‹ค. ์ฆ‰ ์ค€์˜์† ์ƒํƒœ ์—”ํ‹ฐํ‹ฐ์˜ ๋ชจ๋“  ๊ฐ’์„ ์กฐํšŒํ•œ ์˜์†์„ฑ ์—”ํ‹ฐํ‹ฐ์— ๋ฐ€์–ด๋„ฃ๋Š”๋‹ค.
  4. ์˜์† ์ƒํƒœ์ธ ์—”ํ‹ฐํ‹ฐ๋ฅผ ๋ฐ˜ํ™˜ํ•œ๋‹ค.

// Merge
@Transactional
public Item updateItem(Long itemId, Book param){
    //itemId๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœ ์‹ค์ œ DB์— ์žˆ๋Š” ์˜์†์„ฑ ์—”ํ‹ฐํ‹ฐ๋ฅผ ์ฐพ์•„์˜ด
    Item findItem = itemRepository.findOne(itemId);
    findItem.setPrice(param.getPrice());
    findItem.setName(param.getName());
    findItem.setStockQuantity(param.getStockQuantity());
    
    return findItem;
}

merge ์ฃผ์˜์ 

๋ณ€๊ฒฝ ๊ฐ์ง€ ๊ธฐ๋Šฅ์„ ์‚ฌ์šฉํ•˜๋ฉด ์›ํ•˜๋Š” ์†์„ฑ๋งŒ ์„ ํƒํ•ด์„œ ๋ณ€๊ฒฝํ•  ์ˆ˜ ์žˆ์ง€๋งŒ, ๋ณ‘ํ•ฉ์„ ์‚ฌ์šฉํ•˜๋ฉด ๋ชจ๋“  ์†์„ฑ์ด ๋ณ€๊ฒฝ๋œ๋‹ค . ๋ณ‘ํ•ฉ ์‹œ ๊ฐ’์ด ์—†์œผ๋ฉด null๋กœ ์—…๋ฐ์ดํŠธ ํ•  ์œ„ํ—˜๋„ ์žˆ๋‹ค. (๋ณ‘ํ•ฉ์€ ๋ชจ๋“  ํ•„๋“œ๋ฅผ ๊ต์ฒดํ•˜๊ธฐ ๋•Œ๋ฌธ.)

ex) ๊ฐ€๊ฒฉ์ด ํ•œ๋ฒˆ ์ฑ…์ •๋˜๋ฉด ๋ฐ”๊ฟ€ ์ˆ˜ ์—†๋‹ค๊ณ  ๊ฐ€์ •ํ•˜๋ฉด book.setPrice(form.getPrice) ์—†์ด update๋ฅผ ํ•˜๋Š”๋ฐ ์ด๋Œ€๋กœ Merge๋ฅผ ํ˜ธ์ถœํ•ด๋ฒ„๋ฆฌ๋ฉด DB์— Price๋Š” NULL๋กœ ์—…๋ฐ์ดํŠธ ๋˜๋ฒ„๋ฆฐ๋‹ค. (๋งค์šฐ ์œ„ํ—˜.)






โœ๏ธ ๊ฒฐ๋ก  - ์—”ํ‹ฐํ‹ฐ๋ฅผ ๋ณ€๊ฒฝํ•  ๋•Œ๋Š” ํ•ญ์ƒ ๋ณ€๊ฒฝ ๊ฐ์ง€ ์‚ฌ์šฉ

โ— ์ปจํŠธ๋กค๋Ÿฌ์—์„œ ์–ด์„คํ”„๊ฒŒ ์—”ํ‹ฐํ‹ฐ ์ƒ์„ฑ ๊ธˆ์ง€
โ— ํŠธ๋žœ์žญ์…˜์ด ์žˆ๋Š” ์„œ๋น„์Šค ๊ณ„์ธต์— ์‹๋ณ„์ž์™€ ๋ณ€๊ฒฝํ•  ๋ฐ์ดํ„ฐ๋ฅผ ๋ช…ํ™•ํ•˜๊ฒŒ ์ „๋‹ฌ. ํŒŒ๋ผ๋ฏธํ„ฐ๋‚˜ Dto๋กœ
โ— ํŠธ๋žœ์žญ์…˜์ด ์žˆ๋Š” ์„œ๋น„์Šค ๊ณ„์ธต์—์„œ ์˜์† ์ƒํƒœ์˜ ์—”ํ‹ฐํ‹ฐ๋ฅผ ์กฐํšŒํ•˜๊ณ , ์—”ํ‹ฐํ‹ฐ์˜ ๋ฐ์ดํ„ฐ๋ฅผ ์ง์ ‘ ๋ณ€๊ฒฝ
โ— ํŠธ๋žœ์žญ์…˜ ์ปค๋ฐ‹ ์‹œ์ ์— ๋ณ€๊ฒฝ ๊ฐ์ง€๊ฐ€ ์‹คํ–‰๋œ๋‹ค.

ํŒŒ๋ผ๋ฏธํ„ฐ๋กœ ๋ณ€๊ฒฝํ•  ๋ฐ์ดํ„ฐ ๋ช…ํ™•ํ•˜๊ฒŒ ์ „๋‹ฌ
ItemService.class

@Transactional
public void updateItem(Long itemId, String name, int price, int stockQuantity){
    //itemId๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœ ์‹ค์ œ DB์— ์žˆ๋Š” ์˜์†์„ฑ ์—”ํ‹ฐํ‹ฐ๋ฅผ ์ฐพ์•„์˜ด
    Item findItem = itemRepository.findOne(itemId);
    findItem.setName(name);
    findItem.setPrice(price);
    findItem.setStockQuantity(stockQuantity);
}

ItemController.class

@PostMapping("item/{itemId}/edit")
public String updateItem(@PathVariable Long itemId, @ModelAttribute("form") BookForm form) {


    //itemService์—์„œ ํŒŒ๋ผ๋ฏธํ„ฐ๋กœ ํ•„์š”ํ•œ ๊ฐ’๋“ค๋งŒ์„ ๊ฐ€์ ธ์˜ด
    itemService.updateItem(itemId, form.getName(), form.getPrice(), form.getStockQuantity());

    //itemService.saveItem(book);
    return "redirect:items";
}


Dto๋กœ ๋ณ€๊ฒฝํ•  ๋ฐ์ดํ„ฐ ๋ช…ํ™•ํ•˜๊ฒŒ ์ „๋‹ฌ

import lombok.Getter;
import lombok.Setter;

@Getter
@Setter
public class UpdateItemDto {
    private String Name;
    private int price;
    private int stockQuantity;
}


ItemService.class

@Transactional
public void updateItem2(Long itemId, UpdateItemDto itemDto){
    //itemId๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœ ์‹ค์ œ DB์— ์žˆ๋Š” ์˜์†์„ฑ ์—”ํ‹ฐํ‹ฐ๋ฅผ ์ฐพ์•„์˜ด
    Item findItem = itemRepository.findOne(itemId);
    findItem.setName(itemDto.getName());
    findItem.setPrice(itemDto.getPrice());
    findItem.setStockQuantity(itemDto.getStockQuantity());
}


โญ• ์—…๋ฐ์ดํŠธ๋Š” ๋‹จ๋ฐœ์„ฑ์œผ๋กœ set์œผ๋กœ ํ•˜๋ฉด ์ข‹์ง€ ์•Š๋‹ค.

addStock์ด๋‚˜ change์ฒ˜๋Ÿผ ์˜๋ฏธ์žˆ๋Š” ๋ฉ”์„œ๋“œ๋ฅผ ๋งŒ๋“ค์–ด์•ผ์ง€ set์„ ๋ง‰ ๊น”๋ฉด ์ข‹์ง€ ์•Š๋‹ค. ๋ณ€๊ฒฝ ์ง€์ ์ด ์—”ํ‹ฐํ‹ฐ๋กœ ๋‹ค ๊ฐ€๊ธฐ ๋•Œ๋ฌธ์— set์œผ๋กœ ํ•˜๋ฉด ์ถ”์ ์ด ์–ด๋ ต๋‹ค.

@Transactional
public void updateItem2(Long itemId, UpdateItemDto itemDto){
    //itemId๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœ ์‹ค์ œ DB์— ์žˆ๋Š” ์˜์†์„ฑ ์—”ํ‹ฐํ‹ฐ๋ฅผ ์ฐพ์•„์˜ด
    Item findItem = itemRepository.findOne(itemId);
    //findItem.setName(itemDto.getName());
    //findItem.setPrice(itemDto.getPrice());
    
    // ์ด๋Ÿฐ์‹์œผ๋กœ ํ•ด์•ผ ์–ด๋””์„œ ๋ฐ”๋€Œ๋Š”์ง€ ์ถ”์ ์ด ์‰ฌ์›€
    findItem.change(price, name, stockQuantity);
}

addStock์˜ ๊ฒฝ์šฐ Item ์—”ํ‹ฐํ‹ฐ์—์„œ ๊ด€๋ฆฌํ•˜๋Š” stockQuantity๋ฅผ ๋ณ€๊ฒฝํ•˜๋Š” ๋น„์ฆˆ๋‹ˆ์Šค๋กœ์ง์„ ์—”ํ‹ฐํ‹ฐ์—์„œ ์ฒ˜๋ฆฌํ•˜์ž.
์„œ๋น„์Šค ๋‹จ์—์„œ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ์ง€๋งŒ, ์—”ํ‹ฐํ‹ฐ์—์„œ ์ฒ˜๋ฆฌํ•˜๋Š” ๊ฒƒ์ด ์‘์ง‘๋„๊ฐ€ ๋†’์€ ์„ค๊ณ„๋กœ ๋ณผ ์ˆ˜ ์žˆ๋‹ค.



ItemController.class

//ํŒŒ๋ผ๋ฏธํ„ฐ๊ฐ€ ์•„๋‹Œ Dto๋กœ ๋ณ€๊ฒฝํ•  ๋ฐ์ดํ„ฐ๋ฅผ ๋ช…ํ™•ํ•˜๊ฒŒ ์ „๋‹ฌ.
@PostMapping("item/{itemId}/edit")
public String updateItem2(@PathVariable Long itemId, UpdateItemDto itemDto) {
    itemService.updateItem2(itemId, itemDto);

    return "redirect:items";
}





๐Ÿ“– ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์Šคํ‚ค๋งˆ ์ž๋™ ์ƒ์„ฑ

hibernate.hdm2ddl.auto (persistence.xml)์— ์žˆ์Œ

create : ๊ธฐ์กด ํ…Œ์ด๋ธ” ์‚ญ์ œ ํ›„ ๋‹ค์‹œ ์ƒ์„ฑ (DROP + CREATE)

create-drop : create์™€ ๊ฐ™์œผ๋‚˜ ์ข…๋ฃŒ์‹œ์ ์— ํ…Œ์ด๋ธ” DROP

update : ๋ณ€๊ฒฝ๋ถ„๋งŒ ๋ฐ˜์˜ (์šด์˜ DB์—๋Š” ์‚ฌ์šฉ ์•ˆ๋Œ) ๊ทธ๋ฆฌ๊ณ  ์ง€์šฐ๋Š” ๊ฑด ์•ˆ๋˜๊ณ  ์ถ”๊ฐ€๋งŒ ๊ฐ€๋Šฅ

validate : ์—”ํ‹ฐํ‹ฐ์™€ ํ…Œ์ด๋ธ”์ด ์ •์ƒ ๋งคํ•‘๋˜์—ˆ๋Š”์ง€๋งŒ ํ™•์ธ

none : ์‚ฌ์šฉํ•˜์ง€ ์•Š์Œ

์ฃผ์˜์ 
1) ์šด์˜ ์žฅ๋น„์—๋Š” ์ ˆ๋Œ€ create, create-drop, update ์‚ฌ์šฉ ๋ถˆ๊ฐ€
2) ๊ฐœ๋ฐœ ์ดˆ๊ธฐ ๋‹จ๊ณ„๋Š” create or update
3) ํ…Œ์ŠคํŠธ ์„œ๋ฒ„๋Š” update or validate
4) ์Šคํ…Œ์ด์ง•๊ณผ ์šด์˜ ์„œ๋ฒ„๋Š” validate or none

ํ…Œ์ŠคํŠธ ์„œ๋ฒ„, ์šด์˜ ์„œ๋ฒ„๋Š” ๊ฐ€๊ธ‰์  ์“ฐ์ง€ ๋ง๊ธฐ (์“ฐ๊ฒŒ ๋˜๋ฉด ์กฐ์‹ฌํ•ด์„œ)

๊ธฐ๋ณธํ‚ค ๋งคํ•‘ ์ž˜ ์ดํ•ด๊ฐ€ ๊ฐ€์ง€ ์•Š๋Š”๋‹ค.
๋‚˜์ค‘์— ๋‹ค์‹œ ์˜จ๋‹ค.

em.persist ํ•˜๊ณ ๋‚˜๋ฉด ํ•ญ์ƒ id์˜ ๊ฐ’์ด ๋“ค์–ด๊ฐ, ์˜์†์„ฑ ์ƒํƒœ๊ฐ€ ๋˜๋ฉด ๋ฌด์กฐ๊ฑด PK๊ฐ€ ์„ธํŒ…๋˜๊ณ  ์˜์†์„ฑ์ด ๋œ๋‹ค.

Team

public class Team {
    @Id
    @GeneratedValue
    @Column(name = "TEAM_ID")
    private Long id;
    private String name;

    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;
    }
}


Member

@Id @GeneratedValue
@Column(name = "MEMBER_ID")
private Long id;

@Column(name = "USERNAME")
private String username;

//@Column(name = "TEAM_ID")
//private Long teamId;

@ManyToOne//์ผ๋Œ€๋‹ค ๋ผ๋Š” ๊ด€๊ณ„๋กœ Member ์ž…์žฅ์—์„œ Many, Team ์ž…์žฅ์—์„œ One์„ ์ค˜์•ผ ํ•œ๋‹ค.
@JoinColumn(name = "TEAM_ID") //team ์ด๋ž‘ Member ํ…Œ์ด๋ธ”์˜ FK์™€ ๋งคํ•‘์„ ํ•ด์•ผํ•œ๋‹ค.
private Team team; //์—๋Ÿฌ ์ƒ๊ธฐ๋Š” ์ด์œ ๋Š” JPA ์—๊ฒŒ ๋‘˜์˜ ๊ด€๊ณ„๊ฐ€ ์ผ๋Œ€๋‹ค ์ธ์ง€ ๋‹ค๋Œ€๋‹ค์ธ์ง€ ์ด๋Ÿฐ๊ฑธ ์•Œ๋ ค์ค˜์•ผ ํ•œ๋‹ค.

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;
}

public Team getTeam() {
	return team;
}

public void setTeam(Team team) {
	this.team = team;
}





โœ๏ธ ๋‹จ๋ฐฉํ–ฅ ๊ด€๊ณ„

JpaMain

EntityManagerFactory emf = Persistence.createEntityManagerFactory("hello"); //persistence.xml ์—์„œ ์ •ํ•ด๋†“์€ "hello"
//EntityManagerFactory๋ฅผ ๋งŒ๋“œ๋Š” ์ˆœ๊ฐ„ ๋ฐ์ดํ„ฐ๋ฒ ์ด์„œ์™€ ์—ฐ๊ฒฐ๋„ ๋‹ค ๋˜๊ณ  ์›ฌ๋งŒํ•œ๊ฒŒ ๋‹ค ๋จ

EntityManager em = emf.createEntityManager();
//JPA ์—์„œ๋Š” ๊ผญ ํŠธ๋žœ์žญ์…˜์ด๋ผ๋Š” ๋‹จ์œ„๊ฐ€ ๋งค์šฐ ์ค‘์š”ํ•˜๋‹ค.
//๋ฐ์ดํ„ฐ๋ฅผ ๋ณ€๊ฒฝํ•˜๋Š” ๋ชจ๋“  ์ž‘์—…์€ ๊ผญ ํŠธ๋žœ์žญ์…˜ ์•ˆ์—์„œ ์ž‘์—…์„ ํ•ด์•ผํ•œ๋‹ค.

EntityTransaction tx = em.getTransaction();
tx.begin();
        
try{
	//์ €์žฅํ•˜๋Š” ์ฝ”๋“œ
	Team team = new Team();
	team.setName("Team A");
    em.persist(team);

    Member member = new Member();
    member.setUsername("member1");
    member.setTeam(team);
    em.persist(member);

    //์˜์†์„ฑ ์ปจํ…์ŠคํŠธ๊ฐ€ ์•„๋‹Œ DB์—์„œ ๊ฐ€์ ธ์˜จ ์ฟผ๋ฆฌ๋ฅผ ๋ณด๊ณ ์‹ถ๋‹ค๋ฉด
    em.flush();//flush ํ•ด์„œ ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ์— ์žˆ๋Š” ๊ฑธ DB๋กœ ์ฟผ๋ฆฌ ๋‚ ๋ ค๋ฒ„๋ ค์„œ ์‹ฑํฌ ๋งž์ถ”๊ณ 
    em.clear();//์ด๊ฑธ๋กœ ์˜์†์„ฑ์„ ์ดˆ๊ธฐํ™” ์‹œ์ผœ๋ฒ„๋ฆฐ๋‹ค.

    //์กฐํšŒ์ผ ๋•Œ
    Member findMember = em.find(Member.class, member.getId());

    Team findTeam = findMember.getTeam();
    System.out.println("findTeam = " + findTeam.getName());

    tx.commit();
}
catch(Exception e){
	tx.rollback(); //๋ฌธ์ œ๊ฐ€ ์ƒ๊ธฐ๋ฉด ๋กค๋ฐฑ
}

finally{
	em.close();
    //entityManager๊ฐ€ ๊ฒฐ๊ตญ ๋ฐ์ดํ„ฐ ์ปค๋„ฅ์…˜์„ ๋ฌผ๊ณ  ๋™์ž‘ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ๊ผญ ๋‹ซ๋Š”๋‹ค.
}
emf.close();

getTeamId() ์ด๋Ÿฐ ์‹์œผ๋กœ ๊ฐ€์ ธ์˜ค๋Š” ๊ฒƒ์ด ์•„๋‹ˆ๋ผ getTeam() ์œผ๋กœ ๊ฐ€์ ธ์™€์„œ ์ข€ ๋” ๊ฐ์ฒด ์ง€ํ–ฅ์ ์œผ๋กœ ๊ฐ€์ ธ์˜ฌ ์ˆ˜ ์žˆ๋‹ค.
์ข€ ๋” ์ดํ•ด ํ•„์š”

ํŒ€ ์ด๋ฆ„์„ ๋ฐ”๊พธ๊ณ  ์‹ถ๋‹ค๋ฉด DB์— 100๋ฒˆ ์ด๋ผ๋Š” ํŒ€์ด ์žˆ๋‹ค๋Š” ๊ฐ€์ • ํ•˜์—
Team newTeam = em.find(Team.class, 100L);
findMember.setTeam(newTeam);
์ด๋ ‡๊ฒŒ๋งŒ ํ•ด์ฃผ๋ฉด ๋œ๋‹ค.
setTeam ํ•˜๋ฉด DB์˜ ์™ธ๋ž˜ํ‚ค ๊ฐ’์ด ์—…๋ฐ์ดํŠธ ๋œ๋‹ค.






โœ๏ธ ์–‘๋ฐฉํ–ฅ ๊ด€๊ณ„

@OneToMany(mappedBy = "team") //mappedBy๋Š” ์ง€๊ธˆ ์ผ๋Œ€๋‹ค ๋งคํ•‘์—์„œ team์ด๋ž‘ ์—ฐ๊ฒฐ์ด ๋˜์–ด์žˆ๋‹ค๊ณ  ์•Œ๋ ค์ฃผ๋Š” ๊ฒƒ์ด๋‹ค.
private List<Member> members = new ArrayList<>();
try{
	Team team = new Team();
	team.setName("Team A");
    em.persist(team);

    Member member = new Member();
    member.setUsername("member1");
    member.setTeam(team);
    em.persist(member);

     //์˜์†์„ฑ ์ปจํ…์ŠคํŠธ๊ฐ€ ์•„๋‹Œ DB์—์„œ ๊ฐ€์ ธ์˜จ ์ฟผ๋ฆฌ๋ฅผ ๋ณด๊ณ ์‹ถ๋‹ค๋ฉด
     em.flush();//flush ํ•ด์„œ ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ์— ์žˆ๋Š” ๊ฑธ DB๋กœ ์ฟผ๋ฆฌ ๋‚ ๋ ค๋ฒ„๋ ค์„œ ์‹ฑํฌ ๋งž์ถ”๊ณ 
     em.clear();//์ด๊ฑธ๋กœ ์˜์†์„ฑ์„ ์ดˆ๊ธฐํ™” ์‹œ์ผœ๋ฒ„๋ฆฐ๋‹ค.

     //์กฐํšŒ์ผ ๋•Œ
     Member findMember = em.find(Member.class, member.getId());

     List<Member> members = findMember.getTeam().getMembers();

     for (Member m : members) {
     	System.out.println("m = " + m.getUsername());
     }

     tx.commit();
}
     
catch(Exception e){
	tx.rollback(); //๋ฌธ์ œ๊ฐ€ ์ƒ๊ธฐ๋ฉด ๋กค๋ฐฑ
}

finally{
	em.close();
    //entityManager๊ฐ€ ๊ฒฐ๊ตญ ๋ฐ์ดํ„ฐ ์ปค๋„ฅ์…˜์„ ๋ฌผ๊ณ  ๋™์ž‘ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ๊ผญ ๋‹ซ๋Š”๋‹ค.
}
emf.close();

mappedBy

mappedBy๋Š” ์ง€๊ธˆ ์ผ๋Œ€๋‹ค ๋งคํ•‘์—์„œ team์ด๋ž‘ ์—ฐ๊ฒฐ์ด ๋˜์–ด์žˆ๋‹ค๊ณ  ์•Œ๋ ค์ฃผ๋Š” ๊ฒƒ์ด๋‹ค.

์—ฌ๊ธฐ์„œ JoinColumn() ํ•ด์„œ ํ•˜๋Š” ๋ฐฉ๋ฒ•์ด๋ž‘ ๋ญ๊ฐ€ ์ฐจ์ด์ธ์ง€ ์•Œ๊ธฐ๊ฐ€ ์–ด๋ ต๋‹ค.

์–‘๋ฐฉํ–ฅ ๊ด€๊ณ„๋ถ€ํ„ฐ ์•Œ์•„๋ณธ๋‹ค.
๊ฐ์ฒด ์—ฐ๊ด€๊ด€๊ณ„ = 2๊ฐœ๋กœ ํšŒ์› -> ํŒ€ ์—ฐ๊ด€๊ด€๊ณ„ , ํŒ€ -> ํšŒ์› ์—ฐ๊ด€๊ด€๊ณ„
ํ…Œ์ด๋ธ” ์—ฐ๊ด€๊ด€๊ณ„ = 1๊ฐœ๋กœ ํšŒ์› <-> ํŒ€ ์—ฐ๊ด€๊ด€๊ณ„

๊ทธ๋Ÿฐ๋ฐ ์–‘๋ฐฉํ–ฅ ๊ด€๊ณ„๋ผ๋Š” ๊ฒƒ๋ณด๋‹ค ๋‹จ๋ฐฉํ–ฅ ๊ด€๊ณ„ 2๊ฐœ๊ฐ€ ์žˆ๋‹ค๊ณ  ์ดํ•ดํ•˜์ž.
๊ทธ๋ž˜์„œ ๊ฐ์ฒด๋ฅผ ์–‘๋ฐฉํ–ฅ์œผ๋กœ ์ฐธ์กฐํ•˜๋ ค๋ฉด ๋‹จ๋ฐฉํ–ฅ ์—ฐ๊ด€๊ด€๊ณ„๋ฅผ 2๊ฐœ ๋งŒ๋“ค์–ด์•ผ ํ•œ๋‹ค.

ํ…Œ์ด๋ธ”์€ ์™ธ๋ž˜ํ‚ค ํ•˜๋‚˜๋กœ ๋‘ ํ…Œ์ด๋ธ”์˜ ์—ฐ๊ด€๊ด€๊ณ„๋ฅผ ๊ด€๋ฆฌํ•œ๋‹ค.






๐Ÿ“– ์—ฐ๊ด€๊ด€๊ณ„ ์ฃผ์ธ

Member์˜ team ์„ ์—…๋ฐ์ดํŠธ ํ• ์ง€ Team์˜ List members๋ฅผ ์—…๋ฐ์ดํŠธ ํ• ์ง€ ๊ฒฐ์ •์„ ํ•ด์„œ ์™ธ๋ž˜ํ‚ค๋ฅผ ์—…๋ฐ์ดํŠธํ•ด์•ผ ํ•œ๋‹ค. (๋‘˜ ์ค‘ ํ•˜๋‚˜๋กœ ์™ธ๋ž˜ํ‚ค๋ฅผ ๊ด€๋ฆฌํ•ด์•ผ ํ•œ๋‹ค.)
๊ฐ์ฒด์˜ ๋‘ ๊ด€๊ณ„ ์ค‘ ํ•˜๋‚˜๋ฅผ ์—ฐ๊ด€๊ด€๊ณ„์˜ ์ฃผ์ธ์œผ๋กœ ์ง€์ •ํ•œ๋‹ค.
์—ฐ๊ด€๊ด€๊ณ„์˜ ์ฃผ์ธ๋งŒ์ด ์™ธ๋ž˜ํ‚ค๋ฅผ ๊ด€๋ฆฌํ•œ๋‹ค.(๋“ฑ๋ก, ์ˆ˜์ •)
์ฃผ์ธ์ด ์•„๋‹Œ ์ชฝ์€ ์ฝ๊ธฐ๋งŒ ๊ฐ€๋Šฅํ•˜๋‹ค.
์ฃผ์ธ์€ mappedBy ์†์„ฑ ์‚ฌ์šฉ ๋ถˆ๊ฐ€
์ฃผ์ธ์ด ์•„๋‹ˆ๋ฉด mappedBy ์†์„ฑ์œผ๋กœ ์ฃผ์ธ ์ง€์ •.
@JoinColumn์„ ์“ฐ๋Š” ์ชฝ์˜ ํด๋ž˜์Šค๊ฐ€ ์—ฐ๊ด€๊ด€๊ณ„์˜ ์ฃผ์ธ์ด๋‹ค.

์™ธ๋ž˜ํ‚ค๊ฐ€ ์žˆ๋Š” ๊ณณ์„ ์ฃผ์ธ์œผ๋กœ ์ •ํ•ด์•ผ ํ•œ๋‹ค.

์™ธ๋ž˜ํ‚ค๊ฐ€ ์žˆ๋Š” ์ชฝ์ด ํ•ญ์ƒ n ์ด๊ณ  ์—†๋Š” ์ชฝ์ด 1์ด๋‹ค. ๊ทธ๋ž˜์„œ n ์ชฝ์ด ์—ฐ๊ด€๊ด€๊ณ„ ์ฃผ์ธ์ด๋‹ค.
(n ์ชฝ์ด @ManyToOne)

๊ฒฐ๋ก  ->

์œ„ ์ฝ”๋“œ์—์„œ ์—ฐ๊ด€๊ด€๊ณ„ ์ฃผ์ธ์€ Member ๊ฐ์ฒด์— team ์ด๋‹ค.
Team์˜ List<Member> members ๋Š” ๊ฐ์ฒด ๊ด€์ ์—์„œ ์–‘๋ฐฉํ–ฅ ์—ฐ๊ด€๊ด€๊ณ„๋ฅผ ๊ตฌํ˜„ ํ•˜๊ธฐ ์œ„ํ•ด ์ถ”๊ฐ€๋œ ๊ฒƒ์ด๋‹ค.

์ฃผ์ธ์—๊ฒŒ ๋งคํ•‘๋œ members๋Š” ํŠน์„ฑ์ƒ ๋ฐ์ดํ„ฐ๊ฐ€ ๋“ฑ๋ก, ์ˆ˜์ •, ์‚ญ์ œ ๋˜๋”๋ผ๋„ DB์— ๋ฐ˜์˜์ด ๋˜์ง€๋Š” ์•Š๋Š”๋‹ค.
Member์— team์„ ๋ณ€๊ฒฝํ•˜๋ฉด DB์— ๋ฐ˜์˜์€ ๋œ๋‹ค.
๋‹น์—ฐํžˆ ํŒ€์ด ๋ฐ”๋€Œ์—ˆ์œผ๋ฏ€๋กœ Team ๋‚ด members์—์„œ ํŠน์ • member๋ฅผ ์ง€์›Œ์ฃผ์–ด์•ผ ํ•˜์ง€๋งŒ DB๊ด€์ ์—์„œ๋Š” ๊ตณ์ด ์ง€์›Œ์ฃผ์ง€ ์•Š์•„๋„ ๋œ๋‹ค.

์™œ๋ƒํ•˜๋ฉด ์ด๋ฏธ Member๊ฐ€ team์„ ๋ณ€๊ฒฝํ•˜๊ธฐ๋งŒ ํ•ด๋„ Member ํ…Œ์ด๋ธ”์˜ team fk๊ฐ€ ๋ณ€๊ฒฝ๋˜์—ˆ๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.
Team์˜ members๋Š” ์—ฐ๊ด€๊ด€๊ณ„ ์ฃผ์ธ์ด ์•„๋‹ˆ๊ธฐ ๋•Œ๋ฌธ์— members์—์„œ ํŠน์ • member๋ฅผ ์ง€์›Œ๋„ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์—๋Š” ๋ฐ˜์˜๋˜์ง€ ์•Š๋Š”๋‹ค. ๊ฒฐ๋ก ์ ์œผ๋กœ ๊ฐ์ฒด ๊ด€์ ์—์„œ๋Š” ํŒ€์„ ๋ณ€๊ฒฝํ•œ ๋ฉค๋ฒ„๋ฅผ ํŒ€ ๊ฐ์ฒด์˜ ๋ฉค๋ฒ„ ๋ชฉ๋ก์—์„œ ์ง€์›Œ์ฃผ๋Š” ๊ฒŒ ๋งž์ง€๋งŒ ๋ณดํ†ต ๋ณ€๊ฒฝ๋œ ๋ฐ์ดํ„ฐ๋ฅผ ์ฆ‰์‹œ ์‚ฌ์šฉํ•˜๋Š” ๊ฒฝ์šฐ๋Š” ๋“œ๋ฌผ๊ธฐ์— ์ง€์›Œ์ฃผ๋Š” ๋กœ์ง์„ ์ถ”๊ฐ€ํ•˜์ง€ ์•Š์•˜๋‹ค๊ณ  ๋ณด๋ฉด ๋œ๋‹ค.

์ฃผ์˜ -> ์–‘๋ฐฉํ–ฅ ์—ฐ๊ด€ ์„ธํŒ… ์‹œ์—๋Š” ์–‘์ชฝ ๋ชจ๋‘ ๊ฐ’์„ ์„ธํŒ… ํ•ด์ฃผ์–ด์•ผ ํ•œ๋‹ค.

Team team = new Team();
team.setName("Team A");

//team.getMembers().add(member); ์ฃผ์ธ์ด ์•„๋‹Œ ๋ฑกํ–ฅ (์—ญ๋ฐฉํ–ฅ)๋งŒ ์—ฐ๊ด€๊ด€๊ณ„ ์„ค์ •
em.persist(team);

Member member = new Member();
member.setUsername("member1");
member.setTeam(team);
em.persist(member);

team.getMembers().add(member); //์–‘์ชฝ ๋ชจ๋‘ ๊ฐ’์„ ์„ธํŒ…ํ•ด์คŒ
  
Member findMember = em.find(Member.class, member.getId());
List<Member> members = findMember.getTeam().getMembers();

for (Member m : members) {
	System.out.println("m = " + m.getUsername());
}

tx.commit();

Team team = new Team();
team.setName("Team A");
            //team.getMembers().add(member); ์ฃผ์ธ์ด ์•„๋‹Œ ๋ฑกํ–ฅ (์—ญ๋ฐฉํ–ฅ)๋งŒ ์—ฐ๊ด€๊ด€๊ณ„ ์„ค์ •
em.persist(team);

Member member = new Member();
member.setUsername("member1");
member.changeTeam(team);
em.persist(member);
  
Member findMember = em.find(Member.class, member.getId());
List<Member> members = findMember.getTeam().getMembers();

for (Member m : members) {
	System.out.println("m = " + m.getUsername());
}

tx.commit();

Member

public void setTeam(Team team) {
	this.team = team;
    team.getMembers().add(this); //this๋Š” Member ๋‚˜ ์ž์‹ 
}

์ด๋ ‡๊ฒŒ๋„ ๊ฐ€๋Šฅ

member.changeTeam(team) //์„ ์ฃผ์„์ฒ˜๋ฆฌํ•˜๊ณ  (Member.class ์—์„œ๋„ changeTeam() ์ฃผ์„์ฒ˜๋ฆฌ) 
team.addMember(member); //member๋ฅผ ๊ธฐ์ค€์œผ๋กœ ํŒ€์„ ์งค์ง€ ํŒ€์„ ๊ธฐ์ค€์œผ๋กœ ๋ฉค๋ฒ„๋ฅผ ๋„ฃ์„์ง€ ๊ฒฐ์ •
  
public void addMember(Member member) {
	member.setTeam(this);
    members.add(member);
} 
//Team.class ์— ์ด๊ฑฐ ์ถ”๊ฐ€

์–‘๋ฐฉํ–ฅ ๋งคํ•‘ ์‹œ์—๋„ ๋ฌดํ•œ ๋ฃจํ”„ ์กฐ์‹ฌํ•˜์ž.
ex) toString(), lombok, JSON ์ƒ์„ฑ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ


๋‹จ๋ฐฉํ–ฅ ๋งคํ•‘๋งŒ์œผ๋กœ๋„ ์ด๋ฏธ ์—ฐ๊ด€๊ด€๊ณ„ ๋งคํ•‘์ด ์™„๋ฃŒ๋œ๋‹ค.

์–‘๋ฐฉํ–ฅ ๋งคํ•‘์€ ๋ฐ˜๋Œ€ ๋ฐฉํ–ฅ์œผ๋กœ ์กฐํšŒ ๊ธฐ๋Šฅ์ด ์ถ”๊ฐ€๋œ ๊ฒƒ ๋ถ„์ด๋‹ค.






โœ๏ธ ์—ฐ๊ด€๊ด€๊ณ„ ๋งคํ•‘ ์‹œ ๊ณ ๋ ค์‚ฌํ•ญ 3๊ฐ€์ง€

๋‹ค์ค‘์„ฑ, ๋‹จ๋ฐฉํ–ฅ/์–‘๋ฐฉํ–ฅ, ์—ฐ๊ด€๊ด€๊ณ„ ์ฃผ์ธ

์‹คํ–‰ํ•ด๋ณด๋ฉด Update ์ฟผ๋ฆฌ๊ฐ€ ์ถ”๊ฐ€๋กœ ๋‚˜๊ฐ„๋‹ค. ์ด์œ ๋Š”
setName("teamA") ๋ถ€๋ถ„์€ TEAM ํ…Œ์ด๋ธ”์— ๊ทธ๋ƒฅ ๋„ฃ์œผ๋ฉด ๋˜์„œ ๋ฐ”๋กœ ์ˆ˜์ •์ด ๋œ๋‹ค.
team.getMembers().add(member); ๋ถ€๋ถ„์—์„œ team ์—”ํ‹ฐํ‹ฐ๋ฅผ ์ €์žฅํ•˜๋Š”๋ฐ MEMBER ํ…Œ์ด๋ธ”์— ์™ธ๋ž˜ํ‚ค TEAM_ID๋ฅผ ์–ด๋–ป๊ฒŒ ํ•  ๋ฐฉ๋ฒ•์ด ์—†์–ด ์˜† ํ…Œ์ด๋ธ”์—์„œ ๊ฐ€์„œ UPDATE๋ฅผ ์น˜๋Š” ๊ฒƒ์ด๋‹ค. ๊ทธ๋ž˜์„œ ์ฟผ๋ฆฌ๊ฐ€ ํ•œ๋ฒˆ ๋” ๋‚˜๊ฐ„๋‹ค.
๊ทธ๋Ÿฌ๋ฏ€๋กœ ์ผ๋Œ€๋‹ค ๊ด€๊ณ„๋ฅผ ๊ถŒ์žฅํ•˜์ง€ ์•Š๋Š”๋‹ค. (๋‹ค๋Œ€์ผ ๊ถŒ์žฅ)
์—”ํ‹ฐํ‹ฐ๊ฐ€ ๊ด€๋ฆฌํ•˜๋Š” ์™ธ๋ž˜ํ‚ค๊ฐ€ ๋‹ค๋ฅธ ํ…Œ์ด๋ธ”์— ์žˆ๊ณ  ์—ฐ๊ด€๊ด€๊ณ„ ๊ด€๋ฆฌ๋ฅผ ์œ„ํ•ด ์ถ”๊ฐ€๋กœ UPDATE SQL์ด ์‹คํ–‰๋œ๋‹ค.

JPA์—์„œ ์ƒ์†์ด๋ผ๋Š” ๊ด€๊ณ„๋ฅผ ํ•ด๊ฒฐํ•  ์ˆ˜ ์žˆ๋‹ค. (3๊ฐ€์ง€)
*** class Item์€ ์ถ”์ƒ ํด๋ž˜์Šค๋กœ ๋งŒ๋“ค์–ด์•ผ ํ•œ๋‹ค.






โœ๏ธ ์กฐ์ธ ์ „๋žต

@Inheritance(strategy = InheritanceType.JOINED)

JOINED ๋ฐฉ์‹์€ ALBUM, MOVIE, BOOK ํ…Œ์ด๋ธ”์ด Item์˜ PK๋ฅผ ์™ธ๋ž˜ํ‚ค๋กœ ๊ฐ–๋Š” ๋ฐฉ์‹์ด๋‹ค.



@DiscriminatorColumn
๋ถ€๋ชจ ํด๋ž˜์Šค์— ์„ ์–ธํ•˜๊ณ  ๋ถ€๋ชจ ํด๋ž˜์Šค์— ๊ตฌ๋ถ„ ์ปฌ๋Ÿผ์„ ์ง€์ •. ํ•˜์œ„ ํด๋ž˜์Šค๋ฅผ ๊ตฌ๋ถ„ํ•˜๋Š” ์šฉ๋„๋กœ ์“ฐ์ธ๋‹ค. DTYPE์ด ๋ฌด์—‡์ธ์ง€ ์•Œ๋ ค์ค€๋‹ค.
๋ช…ํ™•ํ•˜๊ฒŒ ์–ด๋Š ํด๋ž˜์Šค์— ์กฐ์ธํ–ˆ๋Š”์ง€ ์•Œ๊ธฐ ์œ„ํ•ด์„œ ๋„ฃ์–ด์ฃผ์ž.



@DiscriminatorValue("")
ํ•˜์œ„ ํด๋ž˜์Šค์— ์„ ์–ธํ•œ๋‹ค. ์—”ํ‹ฐํ‹ฐ ์ €์žฅ ์‹œ ๊ตฌ๋ถ„ ์ปฌ๋Ÿผ์— ์ž…๋ ฅํ•  ๊ฐ’์„ ์ง€์ •.
"A" ๋ผ ํ•˜๋ฉด ๋ถ€๋ชจ ํด๋ž˜์Šค์— DTYPE์ด A ๋กœ ์ €์žฅ๋œ๋‹ค.



๐Ÿท๏ธ ์‹ฑ๊ธ€(๋‹จ์ผ) ํ…Œ์ด๋ธ” ์ „๋žต

@Inheritance(strategy = InheritanceType.SINGLE_TABLE)

๋ถ€๋ชจ ํด๋ž˜์Šค์— ์ž์‹ ํ…Œ์ด๋ธ”์˜ ์†์„ฑ๋“ค์„ ๋ชจ๋‘ ๋•Œ๋ ค๋ฐ•์Œ
ALBUM, MOVIE, BOOK ํ…Œ์ด๋ธ”์€ ์ƒ์„ฑ๋˜์ง€ ์•Š์Œ
๊ตณ์ด @DiscriminatorColumn ํ•˜์ง€ ์•Š์•„๋„ DTYPE์ด ๋“ค์–ด๊ฐ€์žˆ์Œ
-> ํ•˜๋‚˜์˜ ํ…Œ์ด๋ธ”์— ๋‹ค ๋“ค์–ด๊ฐ€ ์žˆ๊ธฐ ๋•Œ๋ฌธ์— DTYPE์ด ๋ญ”์ง€ ์•Œ ์ˆ˜๊ฐ€ ์—†๋‹ค. ๊ทธ๋ž˜์„œ ํ•„์ˆ˜๋กœ, ์ž๋™์œผ๋กœ ์ƒ์„ฑ์ด ๋œ๋‹ค.

JpaMain์—์„œ Movie movie์— ์˜ํ•ด์„œ ๋ฐ์ดํ„ฐ ์ƒ์„ฑํ•˜๊ณ  persist ํ•˜๋ฉด ์ฟผ๋ฆฌ๊ฐ€ ํ•œ ๋ฒˆ๋งŒ ๋‚˜๊ฐ„๋‹ค.
์กฐํšŒ๋„ ์กฐ์ธํ•  ํ•„์š”์—†์ด ์ฟผ๋ฆฌ๊ฐ€ ์‹ฌํ”Œํ•˜๊ฒŒ ๋‚˜๊ฐ„๋‹ค.

๊ตฌํ˜„ ํด๋ž˜์Šค๋งˆ๋‹ค ํ…Œ์ด๋ธ” ์ „๋žต

@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)

Item ํ…Œ์ด๋ธ”์ด ์—†๋‹ค. -> ALBUM, MOVIE, BOOK ํ…Œ์ด๋ธ”๋งŒ ์žˆ๋‹ค.
๊ฑฐ์˜ ์“ฐ์ง€ ์•Š์Œ....

์ƒ์†๊ด€๊ณ„ ๋งคํ•‘
๊ด€๊ณ„ํ˜• ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค๋Š” ์ƒ์† ๊ด€๊ณ„X
์Šˆํผํƒ€์ž… ์„œ๋ธŒํƒ€์ž… ๊ด€๊ณ„๋ผ๋Š” ๋ชจ๋ธ๋ง ๊ธฐ๋ฒ•์ด ๊ฐ์ฒด ์ƒ์†๊ณผ ์œ ์‚ฌ
์ƒ์†๊ด€๊ณ„ ๋งคํ•‘ : ๊ฐ์ฒด์˜ ์ƒ์†๊ณผ ๊ตฌ์กฐ์™€ DB์˜ ์Šˆํผํƒ€์ž… ์„œ๋ธŒํƒ€์ž… ๊ด€๊ณ„๋ฅผ ๋งคํ•‘

๊ด€๊ณ„ํ˜• ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค

์Šˆํผํƒ€์ž…, ์„œ๋ธŒํƒ€์ž…

@MappedSuperclass
๋‹ค๋ฅธ ํด๋ž˜์Šค์— ์žˆ๋Š” ์†์„ฑ์„ ๊ฐ™์ด ์“ฐ๊ณ  ์‹ถ์„ ๋•Œ ์‚ฌ์šฉ.
์ฆ‰ ๊ณตํ†ต์ ์œผ๋กœ ์‚ฌ์šฉํ•  ์†์„ฑ์— ์‚ฌ์šฉ.

์ƒ์†๊ด€๊ณ„ ๋งคํ•‘์•„๋‹ˆ๊ณ  ์—”ํ‹ฐํ‹ฐ๋„ ์•„๋‹ˆ๊ณ  ํ…Œ์ด๋ธ”๊ณผ ๋งคํ•‘ํ•˜์ง€๋„ ์•Š๋Š”๋‹ค.
์ƒ์†๋ฐ›๋Š” ์ž์‹ ํด๋ž˜์Šค์— ๋งคํ•‘ ์ •๋ณด๋งŒ ์ œ๊ณตํ•œ๋‹ค.
์ง์ ‘ ์ƒ์„ฑํ•ด์„œ ์‚ฌ์šฉํ•  ์ผ์ด ์—†์œผ๋ฏ€๋กœ ์ถ”์ƒ ํด๋ž˜์Šค ๊ถŒ์žฅ






โœ๏ธ ํ”„๋ก์‹œ

Member findMember = em.getReference(Member.class, member.getId());
System.out.println("findMember = " + findMember.getClass());

๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์กฐํšŒ๋ฅผ ๋ฏธ๋ฃจ๋Š” ๊ฐ€์งœ(ํ”„๋ก์‹œ) ์—”ํ‹ฐํ‹ฐ ๊ฐ์ฒด๋ฅผ ์กฐํšŒํ•œ๋‹ค.

em.find()๋Š” ์ง„์งœ ๊ฐ์ฒด๋ฅผ ์กฐํšŒ.
์‹ค์ œ ํด๋ž˜์Šค๋ฅผ ์ƒ์† ๋ฐ›์•„์„œ ๋งŒ๋“ค์–ด์ง€๊ณ  ์‹ค์ œ ํฌ๋ž˜์Šค์™€ ๊ฒ‰๋ชจ์–‘์ด ๊ฐ™๋‹ค. (ํ…… ๋น„์–ด์žˆ์Œ)

์‚ฌ์šฉํ•˜๋Š” ์ž…์žฅ์—์„œ๋Š” ์ง„์งœ ๊ฐ์ฒด์ธ์ง€ ํ”„๋ก์‹œ ๊ฐ์ฒด์ธ์ง€ ๊ตฌ๋ถ„ํ•˜์ง€ ์•Š๊ณ  ์‚ฌ์šฉํ•˜๋ฉด ๋œ๋‹ค.(์ด๋ก ์ƒ)

ํ”„๋ก์‹œ ๊ฐ์ฒด๋Š” ์‹ค์ œ ๊ฐ์ฒด์˜ ์ฐธ์กฐ๋ฅผ ๋ณด๊ด€ํ•˜๊ณ  ์žˆ์–ด ํ”„๋ก์‹œ ๊ฐ์ฒด๋ฅผ ํ˜ธ์ถœํ•˜๋ฉด ์‹ค์ œ ๊ฐ์ฒด์˜ ๋ฉ”์†Œ๋“œ๋ฅผ ํ˜ธ์ถœํ•˜๊ฒŒ ๋œ๋‹ค.



๐Ÿ’Ž ํ”„๋ก์‹œ ๊ฐ์ฒด์˜ ์ดˆ๊ธฐํ™”


member.getName() ํ˜ธ์ถœํ•  ๋•Œ MemberProxy์— member target์˜ ๊ฐ’์ด ์ฒ˜์Œ์—๋Š” ์—†๋‹ค. ๊ทธ๋Ÿฌ๋ฉด JPA๊ฐ€ ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ์— ์ง„์งœ ๋ฉค๋ฒ„ ๊ฐ์ฒด๋ฅผ ๊ฐ€์ ธ์˜ค๋ผ๋Š” ์š”์ฒญ์„ ํ•œ๋‹ค.

๊ทธ๋Ÿฌ๋ฉด ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ๊ฐ€ DB๋ฅผ ์กฐํšŒํ•ด์„œ ์‹ค์ œ ์—”ํ‹ฐํ‹ฐ ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•ด์„œ Member์—๊ฒŒ ์ค€๋‹ค. ๊ทธ๋ฆฌ๊ณ  MemberProxy์— target์— ์—ฐ๊ฒฐ์‹œ์ผœ์ค€๋‹ค.
-> ๊ฒฐ๊ตญ ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ๋ฅผ ํ†ตํ•ด์„œ ์ดˆ๊ธฐํ™”๋ฅผ ์š”์ฒญํ•˜๋Š” ๊ฒƒ์ด๋‹ค. (DB๋ฅผ ํ†ตํ•ด์„œ ์ง„์งœ ๊ฐ’์„ ๊ฐ€์ง€๊ณ  ์™€์„œ ์ง„์งœ ์—”ํ‹ฐํ‹ฐ๋ฅผ ๋งŒ๋“ค์–ด๋‚ด๋Š” ๊ณผ์ •!! ์ด ์ดˆ๊ธฐํ™”.)



๐Ÿ’Ž ํ”„๋ก์‹œ ํŠน์ง• (์ค‘์š”!!)

  1. ํ”„๋ก์‹œ ๊ฐ์ฒด๋Š” ์ฒ˜์Œ ์‚ฌ์šฉํ•  ๋•Œ ํ•œ ๋ฒˆ๋งŒ ์ดˆ๊ธฐํ™”๊ฐ€ ๋œ๋‹ค. -> ํ•œ ๋ฒˆ ์ดˆ๊ธฐํ™”๋˜๋ฉด ๊ทธ๊ฑธ ๊ณ„์† ์‚ฌ์šฉํ•ด์•ผ ํ•จ.

  2. ํ”„๋ก์‹œ ๊ฐ์ฒด๋ฅผ ์ดˆ๊ธฐํ™”ํ•  ๋•Œ, ํ”„๋ก์‹œ ๊ฐ์ฒด๊ฐ€ ์‹ค์ œ ์—”ํ‹ฐํ‹ฐ๋กœ ๋ฐ”๋€Œ๋Š” ๊ฒƒ์€ ์•„๋‹ˆ๋‹ค. ์ดˆ๊ธฐํ™”๋˜๋ฉด ํ”„๋ก์‹œ ๊ฐ์ฒด๋ฅผ ํ†ตํ•ด์„œ ์‹ค์ œ ์—”ํ‹ฐํ‹ฐ์— ์ ‘๊ทผ ๊ฐ€๋Šฅํ•œ ๊ฒƒ์ด๋‹ค. -> ๊ฐ์ฒด๊ฐ€ ๋‹ค๋ฅธ ๊ฒƒ์œผ๋กœ ๊ต์ฒด๋˜๋Š” ๊ฒƒ์ด ์•„๋‹ˆ๊ณ  Proxy ์œ ์ง€, ๋‚ด๋ถ€์˜ target๋งŒ ๊ฐ’์ด ์ฑ„์›Œ์ง€๋Š” ๊ฒƒ์ด๋‹ค.

  3. ํ”„๋ก์‹œ ๊ฐ์ฒด๋Š” ์›๋ณธ ์—”ํ‹ฐํ‹ฐ๋ฅผ ์ƒ์†๋ฐ›๋Š”๋‹ค. ๋”ฐ๋ผ์„œ ํƒ€์ž… ์ฒดํฌ ์‹œ ์ฃผ์˜ํ•ด์•ผ ํ•œ๋‹ค. -> JPA ์—์„œ ๋‚ด๊ฐ€ Proxy๋ฅผ ์“ธ์ง€ ์•ˆ ์“ธ์ง€ ๋ชจ๋ฅด๊ธฐ ๋•Œ๋ฌธ์—, entity์— ๋Œ€ํ•ด์„œ ๋น„๊ตํ•  ๋•Œ๋Š” == ๋น„๊ต ๋ง๊ณ  instance of๋ฅผ ์‚ฌ์šฉํ•˜์ž.



Member member1 = new Member();
member1.setUsername("member1");
em.persist(member1);

em.flush();
em.clear();

Member m1 = em.find(Member.class, member1.getId());

System.out.println("m1.getClass() = " + m1.getClass()); //์‹ค์ œ ๊ฐ์ฒด

Member reference = em.getReference(Member.class, member1.getId());

System.out.println("reference = " + reference.getClass());
//์ถœ๋ ฅ์ด ๋‘ ๊ฐœ ๋ชจ๋‘ ๊ฐ™๋‹ค๊ณ  ๋‚˜์˜ด
//์ด๋ฏธ Member๋ฅผ ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ์— ์˜ฌ๋ ธ๋Š”๋ฐ(1์ฐจ ์บ์‹œ์— ์žˆ์Œ) ํ”„๋ก์‹œ๋กœ ๊ฐ€์ ธ์™€๋ด์•ผ ์˜๋ฏธ๊ฐ€ ์—†์Œ.

System.out.println("a == a : " + (m1 == reference));

์ด์œ  -> ํ•œ ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ์—์„œ ๊ฐ€์ ธ์™”์œผ๋ฉด JPA๋Š” ํ•ญ์ƒ true๋ฅผ ๋ฐ˜ํ™˜ํ•œ๋‹ค.


  1. ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ์— ์ฐพ๋Š” ์—”ํ‹ฐํ‹ฐ๊ฐ€ ์ด๋ฏธ ์žˆ์œผ๋ฉด em.getReference()๋ฅผ ํ˜ธ์ถœํ•ด๋„ ์‹ค์ œ ์—”ํ‹ฐํ‹ฐ๋ฅผ ๋ฐ˜ํ™˜ํ•œ๋‹ค.
Member refMember = em.getReference(Member.class, member1.getId());
System.out.println("ref = " + refMember.getClass()); //ํ”„๋ก์‹œ๋กœ ๋‚˜์˜ด

Member findMember = em.find(Member.class, member1.getId());
System.out.println("find = " + findMember.getClass()); //์ด๋ฏธ ํ”„๋ก์‹œ๊ฐ€ ๋˜๋ฒ„๋ ค์„œ findํ•ด๋„ ํ”„๋ก์‹œ๊ฐ€ ๋‚˜์˜จ๋‹ค.
            
System.out.println("ref == find : " + (refMember == findMember));

em.find() ํ•ด๋„ ํ”„๋ก์‹œ๊ฐ€ ๋‚˜์˜ฌ ์ˆ˜ ์žˆ๋‹ค.
์ค‘์š”ํ•œ ๊ฒƒ์€ ํ”„๋ก์‹œ๋“  ์•„๋‹ˆ๋“  ๋ฌธ์ œ ์—†๊ฒŒ ๊ฐœ๋ฐœํ•˜๋Š” ๊ฒƒ
์–ด๋–ป๊ฒŒ๋“  true๊ฐ€ ๋˜๋„๋ก ๋งž์ถ”๋ฉด ๋œ๋‹ค



๐Ÿท๏ธ ์‹ค๋ฌด์—์„œ ๋งŽ์ด ๋งŒ๋‚จ

์˜์†์„ฑ ์ปจํ…์ŠคํŠธ์˜ ๋„์›€์„ ๋ฐ›์„ ์ˆ˜ ์—†๋Š” ์ค€์˜์† ์ƒํƒœ์ผ ๋•Œ, ํ”„๋ก์‹œ๋ฅผ ์ดˆ๊ธฐํ™”ํ•˜๋ฉด ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•œ๋‹ค. -> could not initialize proxy (No Session)

Member refMember = em.getReference(Member.class, member1.getId());
System.out.println("ref = " + refMember.getClass()); //ํ”„๋ก์‹œ๋กœ ๋‚˜์˜ด

em.close(); //๊ทธ๋Ÿฐ๋ฐ ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ๋ฅผ ๊บผ๋ฒ„๋ฆฌ๋ฉด ๋˜๋Š” em.detach(refMember)๋กœ ๋„์ง‘์–ด๋‚ผ ๊ฒฝ์šฐ
// em.clear() -> ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ ๊นจ๋—ํ•˜๊ฒŒ ์ง€์›€.

refMember.getUsername(); //DB์— ์ฟผ๋ฆฌ ๋‚˜๊ฐ€๋ฉด์„œ ํ”„๋ก์‹œ ๊ฐ์ฒด๊ฐ€ ์ดˆ๊ธฐํ™” ๋จ

//์ดˆ๊ธฐํ™” ์š”์ฒญ์€ ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ๋ฅผ ํ†ตํ•ด์„œ ์ผ์–ด๋‚œ๋‹ค.
//close๋กœ ์˜์†์„ฑ์„ ๊ด€๋ฆฌํ•˜์ง€ ์•Š๊ฒŒ ๋˜์–ด could not initialize proxy ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ•œ๋‹ค.
//์ฆ‰ ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ๊ฐ€ ์—†๋‹ค๋Š” ์˜๋ฏธ(em.clear() ํ•ด๋„ ๊ฐ™์Œ)

๋”์ด์ƒ refMember๋Š” ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ์˜ ๋„์›€์„ ๋ชป ์คŒ.
ํŠธ๋žœ์žญ์…˜ ์‹œ์ž‘ํ•˜๊ณ  ๋๋‚  ๋•Œ ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ๋„ ์‹œ์ž‘ํ•˜๊ณ  ๋๋‚˜๋„๋ก ๋งž์ถ”๋Š”๋ฐ ํŠธ๋žœ์žญ์…˜ ๋๋‚˜๊ณ ๋‚˜์„œ ํ”„๋ก์‹œ ์กฐํšŒํ•ด ๋ณด๋ฉด no session ํ•˜๊ณ  ์—๋Ÿฌ๊ฐ€ ๋‚˜์˜จ๋‹ค. -> ์š”๊ฑฐ ๋‚ด์šฉ ๊ธฐ์–ต!!!



๐Ÿ’Ž ํ”„๋ก์‹œ ํ™•์ธ

ํ”„๋ก์‹œ ์ธ์Šคํ„ด์Šค์˜ ์ดˆ๊ธฐํ™” ์—ฌ๋ถ€ ํ™•์ธ
getPersistenceUnitUtil().isLoaded(ObjectEntity)

Member refMemebr = em.getReference(Member.class, member1.getId());
System.out.println("refMmeber = " + refMember.getClass()); // Proxy

refMember.getUsername(); // ํ”„๋ก์‹œ ์ดˆ๊ธฐํ™” ํ•ด์คŒ. -> ๊ฐ•์ œ ์ดˆ๊ธฐํ™”
System.out.println(emf.getPersistenceUnitUtil().isLoaded(ObjectEntity));

์ด๋Ÿฌ๋ฉด true๊ฐ€ ์ถœ๋ ฅ๋œ๋‹ค.


ํ”„๋ก์‹œ ํด๋ž˜์Šค ํ™•์ธ ๋ฐฉ๋ฒ•
entity.getClass().getName() ์ถœ๋ ฅ



๐Ÿท๏ธ ์ง€์—ฐ ๋กœ๋”ฉ LAZY๋ฅผ ์‚ฌ์šฉํ•ด์„œ ํ”„๋ก์‹œ๋กœ ์กฐํšŒ

@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn
private Team team;

team์„ ํ”„๋ก์‹œ ๊ฐ์ฒด๋กœ ์กฐํšŒ -> member ํด๋ž˜์Šค ๋งŒ DB์—์„œ ์กฐํšŒํ•œ๋‹ค๋Š” ์˜๋ฏธ.
์ด ๊ฒฝ์šฐ Member๋ฅผ ๊ฑฐ์˜ ์“ฐ๊ณ  Team์€ ๊ฑฐ์˜ ์“ฐ์ง€ ์•Š๋Š” ๊ฒฝ์šฐ์— ์œ ์šฉํ•˜๋‹ค.
๊ทธ๋Ÿฐ๋ฐ Member์™€ Team์„ ๊ฐ™์ด ์“ด๋‹ค๋ฉด LAZY ์ฒ˜๋Ÿผ Member, Team ์ฟผ๋ฆฌ๊ฐ€ 2๋ฒˆ์”ฉ ๋‚˜๊ฐ€๋Š” ๊ฑด ์„ฑ๋Šฅ์ด ํšจ์œจ์ ์ด์ง€ ์•Š๋‹ค.



-> ์ฆ‰์‹œ ๋กœ๋”ฉ Eager ๋ฅผ ์‚ฌ์šฉํ•ด์„œ ํ•จ๊ป˜ ์กฐํšŒํ•œ๋‹ค.

๊ฐ€๊ธ‰์  ์ง€์—ฐ ๋กœ๋”ฉ๋งŒ ์‚ฌ์šฉ(ํŠนํžˆ ์‹ค๋ฌด์—์„œ)
์ฆ‰์‹œ ๋กœ๋”ฉ์„ ์ ์šฉํ•˜๋ฉด ์˜ˆ์ƒํ•˜์ง€ ๋ชปํ•œ SQL์ด ๋ฐœ์ƒ
์ฆ‰์‹œ ๋กœ๋”ฉ์€ JPQL์—์„œ N+1 ๋ฌธ์ œ๋ฅผ ์ผ์œผํ‚จ๋‹ค.

@ManyToOne, @OneToOne ์€ ๊ธฐ๋ณธ์ด ์ฆ‰์‹œ ๋กœ๋”ฉ -> LAZY๋กœ ์„ค์ •
@OneToMany, @ManyToMany(์•ˆ ์“ฐ์ง€๋งŒ) ๋Š” ๊ธฐ๋ณธ์ด ์ง€์—ฐ ๋กœ๋”ฉ (LAZY) ์„ค์ • ํ•„์š”x






โœ๏ธ ์˜์†์„ฑ ์ „์ด: CASCADE

์˜์†์„ฑ ์ „์ด๋Š” ์˜์† ์ƒํƒœ๋กœ ๋งŒ๋“ค ๋•Œ ์—ฐ๊ด€๋œ ์—”ํ‹ฐํ‹ฐ๋„ ํ•จ๊ป˜ ์˜์† ์ƒํƒœ๋กœ ๋งŒ๋“ค๊ณ  ์‹ถ์„ ๋•Œ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด๋‹ค.
๋ถ€๋ชจ๋ฅผ ์ €์žฅํ•  ๋•Œ ์ž์‹๋„ ๊ฐ™์ด ์ €์žฅํ•˜๊ณ  ์‹ถ์„ ๋•Œ ์‚ฌ์šฉ, ์—ฐ๊ด€๊ด€๊ณ„๋‚˜ ์ง€์—ฐ/์ฆ‰์‹œ ๋กœ๋”ฉ๊ณผ๋Š” ์•„๋ฌด ๊ด€๊ณ„๊ฐ€ ์—†๋‹ค.
-> ๋ถ€๋ชจ๋ฅผ ์ €์žฅํ•  ๋•Œ ์—ฐ๊ด€๋œ ์ž์‹๋„ ํ•จ๊ป˜ ๋‹ค persist๋กœ ํ˜ธ์ถœํ•˜๊ณ  ์‹ถ์„ ๋•Œ ์“ด๋‹ค. (๊ทธ์ € ํŽธ๋ฆฌํ•จ๋งŒ ์ œ๊ณตํ•  ๋ฟ)

์ •ํ™•ํ•œ ๊ฐœ๋…์€ ํŠน์ • ์—”ํ‹ฐํ‹ฐ๋ฅผ ์˜์† ์ƒํƒœ๋กœ ๋งŒ๋“ค ๋•Œ, ์—ฐ๊ด€๋œ ์—”ํ‹ฐํ‹ฐ๋„ ํ•จ๊ป˜ ์˜์† ์ƒํƒœ๋กœ ๋งŒ๋“ค๊ณ  ์‹ถ์„ ๋•Œ ์‚ฌ์šฉํ•œ๋‹ค. child ๋“ค์˜ parent ๊ฐ€ ํ•˜๋‚˜์ผ ๋•Œ๋งŒ ์‚ฌ์šฉํ•œ๋‹ค.

๊ฐ„๋‹จํ•˜๊ฒŒ persist๋ฅผ ํ•  ๋•Œ

em.persist(parent);
em.persist(child1);
em.persist(child2);

๋ฅผ ํ•˜์ง€ ์•Š๊ณ  cascade = CascadeType.ALL ์„ ์“ฐ๋ฉด em.persist(parent); ๋งŒ ์จ๋„ ์ž๋™์œผ๋กœ child1,2 ๊ฐ€ ๋ชจ๋‘ persist ๋œ๋‹ค.

cascade = CascadeType.ALL : ๋ชจ๋‘ ์ ์šฉ
cascade = CascadeType.PERSIST : ์˜์† (๋”ฑ ์ €์žฅํ•  ๋•Œ๋งŒ ๋ผ์ดํ”„ ์‚ฌ์ดํด ๋งž์ถ”๊ณ  ๋‚˜๋จธ์ง€๋Š” ์œ„ํ—˜ํ•˜๋‹ˆ ๋”ฐ๋กœ ๋‘๊ณ  ์‹ถ์„ ๋•Œ)
cascade = CascadeType.REMOVE : ์‚ญ์ œ



๐Ÿ“ฃ ์–ธ์ œ ์‚ฌ์šฉํ•˜๋ƒ

๊ฒŒ์‹œํŒ๊ณผ ํŒŒ์ผ ํ…Œ์ด๋ธ”์ด ์žˆ์„ ๋•Œ ์ฒจ๋ถ€ํŒŒ์ผ ๊ฒฝ๋กœ๊ฐ€ ์žˆ์„ ๊ฒฝ์šฐ๋Š” ์ƒ๊ด€์—†์ง€๋งŒ ํŒŒ์ผ์„ ์—ฌ๋Ÿฌ ๊ตฐ๋ฐ์—์„œ ๊ด€๋ฆฌํ•˜๊ฑฐ๋‚˜ ๋‹ค๋ฅธ ์—”ํ‹ฐํ‹ฐ์—์„œ ๊ด€๋ฆฌํ•˜๋Š” ๊ฒฝ์šฐ์—๋Š” ์‚ฌ์šฉํ•˜๋ฉด ์•ˆ๋œ๋‹ค.
์˜ˆ๋ฅผ ๋“ค์–ด Parent๋ผ๋Š” ์—”ํ‹ฐํ‹ฐ๋งŒ child๋ฅผ ๊ด€๋ฆฌํ•˜๊ฑฐ๋‚˜ ์—ฐ๊ด€ํ•œ๊ฒŒ ์žˆ์œผ๋ฉด ์ƒ๊ด€์—†์ง€๋งŒ child๊ฐ€ ๋‹ค๋ฅธ ์—”ํ‹ฐํ‹ฐ์™€ ๊ด€๊ณ„๊ฐ€ ์žˆ๋Š” ๊ฒฝ์šฐ์—๋Š” ์‚ฌ์šฉํ•˜๋ฉด ์•ˆ ๋œ๋‹ค.
Parent๋ผ๋Š” ์—”ํ‹ฐํ‹ฐ๋งŒ child๋ฅผ ์†Œ์œ ํ•  ๋•Œ ์‚ฌ์šฉํ•˜๊ณ  ๋‹ค๋ฅธ ๋ฐ์„œ child๋ฅผ ์†Œ์œ ํ•˜๋Š” ๊ฒฝ์šฐ์—๋Š” ์‚ฌ์šฉ X.






โœ๏ธ ๊ณ ์•„ ๊ฐ์ฒด orphanRemoval = true

๊ณ ์•„ ๊ฐ์ฒด ์ œ๊ฑฐ-> ๋ถ€๋ชจ ์—”ํ‹ฐํ‹ฐ์™€ ์—ฐ๊ด€์ด ๋Š์–ด์ง„ ์ž์‹ ์—”ํ‹ฐํ‹ฐ๋ฅผ ์ž๋™์œผ๋กœ ์‚ญ์ œ.
์ฐธ์กฐ๊ฐ€ ์ œ๊ฑฐ๋œ ์—”ํ‹ฐํ‹ฐ๋Š” ๋‹ค๋ฅธ ๊ณณ์—์„œ ์ฐธ์กฐํ•˜์ง€ ์•Š๋Š” ๊ณ ์•„ ๊ฐ์ฒด๋กœ ๋ณด๊ณ  ์‚ญ์ œํ•˜๋Š” ๊ธฐ๋Šฅ.
์ฐธ์กฐํ•˜๋Š” ๊ณณ์ด ํ•˜๋‚˜์ด๊ณ  ํŠน์ • ์—”ํ‹ฐํ‹ฐ๊ฐ€ ๊ฐœ์ธ ์†Œ์œ ํ•  ๋•Œ(๋ถ€๋ชจ๊ฐ€ ํ•˜๋‚˜.) ์‚ฌ์šฉํ•œ๋‹ค.

@OneToOne, @OneToMany ์—์„œ๋งŒ ์‚ฌ์šฉ ๊ฐ€๋Šฅ!!.

ํŠน์ • ์—”ํ‹ฐํ‹ฐ๊ฐ€ ๊ฐœ์ธ ์†Œ์œ ํ•  ๋•Œ๋งŒ ์‚ฌ์šฉ.



๐Ÿท๏ธ ์˜์†์„ฑ ์ „์ด + ๊ณ ์•„ ๊ฐ์ฒด ๋ชจ๋‘ ํ‚ฌ ๊ฒฝ์šฐ

CascadeType.ALL + orphanRemoval = true
๋‘ ์˜ต์…˜์„ ๋ชจ๋‘ ํ™œ์„ฑํ™”ํ•˜๋ฉด ๋ถ€๋ชจ ์—”ํ‹ฐํ‹ฐ๋ฅผ ํ†ตํ•ด์„œ ์ž์‹์˜ ์ƒ๋ช…์ฃผ๊ธฐ๋ฅผ ๊ด€๋ฆฌํ•  ์ˆ˜ ์žˆ๋‹ค.



๐Ÿท๏ธ cascade, orphanRemoval ๋ช…ํ™•ํ•œ ์ฐจ์ด

  1. orphanRemoval=true๋Š” ๊ด€๊ณ„๊ฐ€ ๋Š์–ด์ง„ child๋ฅผ ์ž๋™์œผ๋กœ ์ œ๊ฑฐํ•œ๋‹ค.
  2. CascadeType.REMOVE๋Š” ๊ด€๊ณ„๊ฐ€ ๋Š์–ด์ง„ child๋ฅผ ์ž๋™ ์ œ๊ฑฐํ•˜์ง€ ์•Š๋Š”๋‹ค. ๊ด€๊ณ„๊ฐ€ ๋Š์–ด์กŒ๋‹ค๋Š” ๊ฒƒ์„ ์ œ๊ฑฐ๋กœ ๋ณด์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค
    ๐Ÿ”— https://tecoble.techcourse.co.kr/post/2021-08-15-jpa-cascadetype-remove-vs-orphanremoval-true/

๐Ÿ’Ž ์ฐธ๊ณ 
๋ถ€๋ชจ๋ฅผ ์ œ๊ฑฐํ•˜๋ฉด ์ž์‹์€ ๊ณ ์•„๊ฐ€ ๋œ๋‹ค. ๋”ฐ๋ผ์„œ ๊ฐ์ฒด ์ œ๊ฑฐ ๊ธฐ๋Šฅ์„ ํ™œ์„ฑํ™”ํ•˜๋ฉด ๋ถ€๋ชจ๋ฅผ ์ œ๊ฑฐํ•  ๋•Œ ์ž์‹๋„ ํ•จ๊ป˜ ์ œ๊ฑฐ๊ฐ€ ๋œ๋‹ค. CascadeType.REMOVE์ฒ˜๋Ÿผ ๋™์ž‘ํ•จ


๋ถ€๋ชจ ์—”ํ‹ฐํ‹ฐ์—์„œ ์ž์‹ ์—”ํ‹ฐํ‹ฐ ์ œ๊ฑฐ
CascadeType.REMOVE๋Š” ์ž์‹ ์—”ํ‹ฐํ‹ฐ๊ฐ€ ๊ทธ๋Œ€๋กœ ๋‚จ์•„์žˆ๋Š” ๋ฐ˜๋ฉด, orphanRemoval = true๋Š” ์ž์‹ ์—”ํ‹ฐํ‹ฐ๋ฅผ ์ œ๊ฑฐํ•œ๋‹ค.



โœ๏ธ ์ž„๋ฒ ๋””๋“œ ํƒ€์ž…(๋ณตํ•ฉ ๊ฐ’ ํƒ€์ž…), ๊ฐ’ ํƒ€์ž… ์ปฌ๋ ‰์…˜์ด ์ค‘์š”

โ— ๊ธฐ๋ณธ๊ฐ’ ํƒ€์ž… -> String, int, ...
์ƒ๋ช…์ฃผ๊ธฐ๋ฅผ ์—”ํ‹ฐํ‹ฐ์˜ ์˜์กด
ex) ํšŒ์›์„ ์‚ญ์ œํ•˜๋ฉด ์ด๋ฆ„, ๋‚˜์ด ํ•„๋“œ๋„ ํ•จ๊ป˜ ์‚ญ์ œ๋จ

๊ฐ’ ํƒ€์ž…์€ ๊ณต์œ ํ•˜๋ฉด X
ex) ํšŒ์› ์ด๋ฆ„ ๋ณ€๊ฒฝ ์‹œ ๋‹ค๋ฅธ ํšŒ์›์˜ ์ด๋ฆ„๋„ ํ•จ๊ป˜ ๋ณ€๊ฒฝ๋˜๋ฉด ์•ˆ๋จ.



โ— ์ž„๋ฒ ๋””๋“œ ํƒ€์ž…(๋ณตํ•ฉ ๊ฐ’ ํƒ€์ž…)
์ƒˆ๋กœ์šด ๊ฐ’ ํƒ€์ž…์„ ์ง์ ‘ ์ •์˜ํ•  ์ˆ˜ ์žˆ์Œ
JPA๋Š” ์ž„๋ฒ ๋””๋“œ ํƒ€์ž…์ด๋ผ ํ•จ
int, String๊ณผ ๊ฐ™์€ ๊ฐ’ ํƒ€์ž… (์—”ํ‹ฐํ‹ฐ ํƒ€์ž…์ด ์•„๋‹˜)

  • ๊ธฐ๋ณธ ์ƒ์„ฑ์ž ํ•„์ˆ˜
  • ์ž„๋ฒ ๋””๋“œ ํƒ€์ž…์€ ์—”ํ‹ฐํ‹ฐ์˜ ๊ฐ’์ผ ๋ฟ์ด๋‹ค.
  • ์ž„๋ฒ ๋””๋“œ ํƒ€์ž…์„ ์‚ฌ์šฉํ•˜๊ธฐ ์ „๊ณผ ํ›„์— ๋งคํ•‘ํ•˜๋Š” ํ…Œ์ด๋ธ”์€ ๊ฐ™๋‹ค.
  • ๊ฐ์ฒด์™€ ํ…Œ์ด๋ธ”์„ ์•„์ฃผ ์„ธ๋ฐ€ํ•˜๊ฒŒ(find-grained) ๋งคํ•‘ํ•˜๋Š” ๊ฒƒ์ด ๊ฐ€๋Šฅ
  • ์ž˜ ์„ค๊ณ„ํ•œ ORM ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์€ ๋งคํ•‘ํ•œ ํ…Œ์ด๋ธ”์˜ ์ˆ˜๋ณด๋‹ค ํด๋ž˜์Šค์˜ ์ˆ˜๊ฐ€ ๋” ๋งŽ์Œ

@Embeddable : ๊ฐ’ ํƒ€์ž…์„ ์ •์˜ํ•˜๋Š” ๊ณณ์— ํ‘œ์‹œ
@Embedded : ๊ฐ’ ํƒ€์ž…์„ ์‚ฌ์šฉํ•˜๋Š” ๊ณณ์— ํ‘œ์‹œ

์‚ฌ์šฉ ์ด์œ 

private String city;
private String street;
private String zipcode;

โ—Address ํด๋ž˜์Šค์— 3๊ฐœ์˜ ๋ฐ์ดํ„ฐ๋ฅผ 1๊ฐœ์˜ ์ฃผ์†Œ๋ผ๋Š” ์˜๋ฏธ์˜ ๊ฐ์ฒด๋กœ ํ‘œํ˜„ํ•œ๋‹ค๋ฉด ํ›จ์”ฌ ๋” ๊ฐ€๋…์„ฑ์žˆ๊ณ  ๊ฐ์ฒด ์ง€ํ–ฅ์ ์ธ ์ฝ”๋“œ๋กœ ๋งŒ๋“ค ์ˆ˜ ์žˆ๋‹ค.



๐Ÿท๏ธ AttributeOverride ํ•œ ์—”ํ‹ฐํ‹ฐ์—์„œ ๊ฐ™์€ ๊ฐ’ ํƒ€์ž…์„ ์‚ฌ์šฉํ•  ๋•Œ

์ปฌ๋Ÿผ๋ช…์ด ์ค‘๋ณต๋จ

@Embedded
private Address homeAddress;

//์ฃผ์†Œ
@Embedded
@AttributeOverrides({
@AttributeOverride(name = "city", column = @Column(name = "WORK_CITY")),
            @AttributeOverride(name = "street",
                    column = @Column(name = "WORK_STREET")),
            @AttributeOverride(name = "zipcode",
                    column = @Column(name = "WORK_ZIPCODE")),
    })

private Address WorkAddress; //์ด๋ ‡๊ฒŒ ์“ฐ๋ฉด ์ค‘๋ณต์ด ์ผ์–ด๋‚˜ ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒ -> AttributeOverride ์‚ฌ์šฉ

์ž„๋ฒ ๋””๋“œ ํƒ€์ž…๊ฐ’์ด null์ด๋ฉด ๋งคํ•‘ํ•œ ์ปฌ๋Ÿผ๊ฐ’์€ ๋ชจ๋‘ null



โœ๏ธ ๊ฐ’ ํƒ€์ž…๊ณผ ๋ถˆ๋ณ€ ๊ฐ์ฒด

๊ฐ’ ํƒ€์ž…์€ ๋ณต์žกํ•œ ๊ฐ์ฒด ์„ธ์ƒ์„ ์กฐ๊ธˆ์ด๋ผ๋„ ๋‹จ์ˆœํ™”ํ•˜๋ ค๊ณ  ๋งŒ๋“  ๊ฐœ๋…์ด๋‹ค.

Address address = new Address("city", "street", "100012");

Member member = new Member();
member.setUsername("member1");
member.setHomeAddress(address);
em.persist(member);

Member member2 = new Member();
member.setUsername("member2");
member.setHomeAddress(address);
em.persist(member2);

member.getHomeAddress().setCity("newCity");

๊ฐ’ ํƒ€์ž… ๊ณต์œ  ์ฐธ์กฐ๋Š” ์ž„๋ฒ ๋””๋“œ ํƒ€์ž… ๊ฐ™์€ ๊ฐ’ ํƒ€์ž…์„ ์—ฌ๋Ÿฌ ์—”ํ‹ฐํ‹ฐ์—์„œ ๊ณต์œ ํ•˜๋ฉด ๋ถ€์ž‘์šฉ์ด ๋ฐœ์ƒํ•œ๋‹ค. -> ๊ฐ™์ด ๊ณต์œ ํ•ด์„œ ์‚ฌ์šฉํ•˜๊ณ  ์‹ถ๋‹ค๋ฉด ์—”ํ‹ฐํ‹ฐ ๊ฐ’ ํƒ€์ž… ์‚ฌ์šฉ, ์•„๋‹ˆ๋ฉด ๋Œ€์‹  ๊ฐ’(์ธ์Šคํ„ด์Šค)๋ฅผ ๋ณต์‚ฌํ•ด์„œ ์‚ฌ์šฉ.


Address address = new Address("city", "street", "1000");

member1 ~~
member2 ~~

member.getHomeAddress().setCity("newCity");

์ด๋ ‡๊ฒŒ ์žˆ์œผ๋ฉด update ์ฟผ๋ฆฌ๊ฐ€ 2๋ฒˆ ๋‚˜๊ฐ€์„œ member1, 2 ๋‘˜ ๋‹ค newcity๋กœ ์ˆ˜์ •๋œ๋‹ค.
์ด๋Ÿฐ ๊ฑธ ์‚ฌ์ด๋“œ ์ดํŽ™ํŠธ๋ผ๊ณ  ํ•˜๋Š”๋ฐ ์ด ๋ฒ„๊ทธ๋Š” ์ง„์งœ ์žก๊ธฐ๊ฐ€ ์–ด๋ ต๋‹ค.
๊ทธ๋ž˜์„œ address๊ฐ€ ์žˆ์œผ๋ฉด new address ๋ผ๋Š” ๊ฒƒ์„ ๋ณต์‚ฌํ•ด์„œ ๋งŒ๋“ค์–ด ์จ์•ผ ํ•œ๋‹ค.


Address address = new Address("city", "street", "100012");

Member member = new Member();
member.setUsername("member1");

member.setHomeAddress(address);
em.persist(member);

//์ด๋ ‡๊ฒŒ ๋ณต์‚ฌ
Address copyAddress = new Address(address.getCity(), address.getStreet(), address.getZipcode());

Member member2 = new Member();
member.setUsername("member2");

member.setHomeAddress(copyAddress);
em.persist(member2);

//์ฒซ ๋ฒˆ์งธ๋งŒ newCity๊ฐ€ ๋˜๊ณ  ๋‘ ๋ฒˆ์งธ๋Š” city๊ฐ€ ๋œ๋‹ค.
member.getHomeAddress().setCity("newCity"); 

ํ•ญ์ƒ ๊ฐ’์„ ๋ณต์‚ฌํ•ด์„œ ์‚ฌ์šฉํ•˜๋ฉด ๊ณต์œ  ์ฐธ์กฐ๋กœ ์ธํ•ด ๋ฐœ์ƒํ•˜๋Š” ๋ถ€์ž‘์šฉ์„ ํ”ผํ•  ์ˆ˜ ์žˆ์ง€๋งŒ ์ž„๋ฒ ๋””๋“œ ํƒ€์ž…์ฒ˜๋Ÿผ ์ง์ ‘ ์ •์˜ํ•œ ๊ฐ’ ํƒ€์ž…์€ ์ž๋ฐ”์˜ ๊ธฐ๋ณธ ํƒ€์ž…์ด ์•„๋‹ˆ๋ผ ๊ฐ์ฒด ํƒ€์ž…์ด๋‹ค.

๊ฐ์ฒด ํƒ€์ž…์€ ์ฐธ์กฐ ๊ฐ’์„ ์ง์ ‘ ๋Œ€์ž…ํ•˜๋Š” ๊ฒƒ์„ ๋ง‰์„ ๋ฐฉ๋ฒ•์ด ์—†๋‹ค.
๊ฐ์ฒด์˜ ๊ณต์œ  ์ฐธ์กฐ๋Š” ํ”ผํ•  ์ˆ˜ ์—†๋‹ค.

์ฆ‰ ๊ธฐ๋ณธ ํƒ€์ž…์€ ๊ฐ’์„ ๋ณต์‚ฌํ•˜์ง€๋งŒ ๊ฐ์ฒด ํƒ€์ž…์€ ์ฐธ์กฐ(์ฃผ์†Œ ๊ฐ’)๋ฅผ ์ „๋‹ฌํ•œ๋‹ค. ๊ทธ๋ž˜์„œ ๊ฐ์ฒด ๋‘˜ ๋‹ค ๊ฐ€ ๋ชจ๋‘ ๋ฐ”๋€๋‹ค.

๊ทธ๋ž˜์„œ ๊ฐ์ฒด ํƒ€์ž…์„ ์ˆ˜์ •ํ•  ์ˆ˜ ์—†๊ฒŒ ๋งŒ๋“ ๋‹ค.






๐Ÿ’Ÿ ๋ถˆ๋ณ€ ๊ฐ์ฒด๋ž€

์ƒ์„ฑ ์‹œ์  ์ดํ›„ ์ ˆ๋Œ€ ๊ฐ’์„ ๋ณ€๊ฒฝํ•  ์ˆ˜ ์—†๋Š” ๊ฐ์ฒด๋กœ ๊ฐ’ ํƒ€์ž…์€ ๋ถˆ๋ณ€ ๊ฐ์ฒด๋กœ ์„ค๊ณ„ํ•ด์•ผํ•œ๋‹ค.
์ƒ์„ฑ์ž๋กœ๋งŒ ๊ฐ’์„ ์„ค์ •ํ•˜๊ณ  ์ˆ˜์ •์ž(Setter)๋ฅผ ๋งŒ๋“ค์ง€ ์•Š์œผ๋ฉด ๋œ๋‹ค. (์•„๋‹ˆ๋ฉด Setter๋ฅผ public์ด ์•„๋‹Œ private ์œผ๋กœ ์ƒ์„ฑํ•ด๋„ ๋จ)

// ์ˆ˜์ •ํ•˜๊ณ  ์‹ถ๋‹ค๋ฉด
Address newAddress = new Address("New City", address.getStreet(), address.getZipcode());
member.setHomeAddress(newAddress);

๊ฐ’ ํƒ€์ž…์€ ๊น”๋”ํ•˜๊ฒŒ ๊ทธ๋ƒฅ ๋ชจ๋‘ ๋ถˆ๋ณ€์œผ๋กœ ๋งŒ๋“ ๋‹ค๊ณ  ์ƒ๊ฐํ•˜์ž






โœ๏ธ JPQL

๊ฐ์ฒด ์ง€ํ–ฅ ์ฟผ๋ฆฌ ์–ธ์–ด์ด๋‹ค. ํ…Œ์ด๋ธ”์ด ์•„๋‹Œ ์—”ํ‹ฐํ‹ฐ ๊ฐ์ฒด๋ฅผ ๋Œ€์ƒ์œผ๋กœ ์ฟผ๋ฆฌํ•œ๋‹ค.
SQL์„ ์ถ”์ƒํ™”ํ•ด์„œ ํŠน์ •๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค SQL์— ์˜์กดํ•˜์ง€ ์•Š๋Š”๋‹ค.
๊ฒฐ๊ตญ SQL๋กœ ๋ณ€ํ™˜๋œ๋‹ค.

JPQL ๋ฌธ๋ฒ• ์ž˜ ์•Œ๋ฉด QueryDSL(์‹ค๋ฌด ์‚ฌ์šฉ ๊ถŒ์žฅ) ์ž˜ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.
JPA ์‚ฌ์šฉํ•˜๋ฉด์„œ JDBC ์ปค๋„ฅ์…˜์„ ์ง์ ‘ ์‚ฌ์šฉํ•˜๊ฑฐ๋‚˜ ์Šคํ”„๋ง JdbcTemplate, Mybatis ๋“ฑ์„ ํ•จ๊ป˜ ์‚ฌ์šฉ ๊ฐ€๋Šฅ.
โ— ๋‹จ ์˜์†์„ฑ ์ปคํ…์ŠคํŠธ๋ฅผ ์ ์ ˆํ•œ ์‹œ์ ์— ๊ฐ•์ œ๋กœ flush() ํ•„์š”.

Member member = new Member();
member.setUsername("member1");
m.persist(member);
  
//flush๋Š” commit ๋  ๋•Œ์™€ query ๊ฐ€ ๋‚ ๋ผ๊ฐˆ ๋•Œ flush ๋œ๋‹ค.
em.flush();
dbconn.executeQuery("select ~"); //flush ํ•˜์ง€ ์•Š์œผ๋ฉด DB์— ์•„๋ฌด๊ฒƒ๋„ ์—†๋Š” ์ƒํƒœ๋ผ ๊ฒฐ๊ณผ๊ฐ€ 0์ด ๋œ๋‹ค.


๐Ÿท๏ธ flush

โ— ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ์˜ ๋ณ€๊ฒฝ ๋‚ด์šฉ์„ DB์— ๋ฐ˜์˜ํ•˜๋Š” ๊ฒƒ์ด๋‹ค.
โ— Transaction commit์ด ์ผ์–ด๋‚  ๋•Œ flush๊ฐ€ ๋™์ž‘ํ•˜๋Š”๋ฐ ์ด ๋•Œ ์“ฐ๊ธฐ ์ง€์—ฐ ์ €์žฅ์†Œ์— ์Œ“์•„ ๋†จ๋˜ INSERT, UPDATE, DELETE SQL๋“ค์ด DB์— ๋‚ ๋ผ๊ฐ„๋‹ค.
์˜์†์„ฑ ์ปจํ…์ŠคํŠธ๊ฐ€ ๋น„์›Œ์ง€๋Š” ๊ฒƒ์ด ์•„๋‹˜

em.persist(member) ํ•  ๋•Œ๋Š” member ๊ฐ์ฒด๊ฐ€ ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ์— ์žˆ๊ณ  DB์—๋Š” ์•„์ง ๋‚ ๋ผ๊ฐ€์ง€ ์•Š์€ ์ƒํƒœ์ด๋‹ค. ๊ทธ๋ž˜์„œ ๊ฐ•์ œ๋กœ em.flush()๋ฅผ ํ•ด์ค€๋‹ค.






โœ๏ธ ๊ฐ’ ํƒ€์ž… ์ปฌ๋ ‰์…˜

๊ฐ’ ํƒ€์ž…์„ ํ•˜๋‚˜ ์ด์ƒ ์ €์žฅํ•  ๋•Œ ์‚ฌ์šฉ
@ElementCollection, @CollectionTable ์‚ฌ์šฉ
๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค๋Š” ์ปฌ๋ ‰์…˜์„ ๊ฐ™์€ ํ…Œ์ด๋ธ”์— ์ €์žฅํ•  ์ˆ˜ ์—†๋‹ค.
->์ปฌ๋ ‰์…˜๋“ค์€ ์ผ๋Œ€๋‹ค ๊ฐœ๋…์ด๊ธฐ ๋•Œ๋ฌธ์— DB์•ˆ์— ์ปฌ๋ ‰์…˜์„ ํ•œ ํ…Œ์ด๋ธ”์— ๋„ฃ์„ ๋ฐฉ๋ฒ•์ด ์—†๋‹ค.

๊ทธ๋ž˜์„œ ์ผ๋Œ€๋‹ค์˜ ๋ณ„๋„์˜ ํ…Œ์ด๋ธ”์„ ๋งŒ๋“ค์–ด ๋‚ด์•ผ ํ•œ๋‹ค.
์ปฌ๋ ‰์…˜์„ ์ €์žฅํ•˜๊ธฐ ์œ„ํ•œ ๋ณ„๋„์˜ ํ…Œ์ด๋ธ”์ด ํ•„์š”ํ•จ.

Set๊ณผ List์ฒ˜๋Ÿผ ์ปฌ๋ ‰์…˜์„ ๊ด€๊ณ„ํ˜• DB์—๋Š” ๊ธฐ๋ณธ์ ์œผ๋กœ ํ…Œ์ด๋ธ” ์•ˆ์— ์ปฌ๋ ‰์…˜์„ ๋‹ด์„ ์ˆ˜ ์žˆ๋Š” ๊ตฌ์กฐ๊ฐ€ ์—†๋‹ค. ๊ทธ๋ƒฅ Value๋กœ ๊ฐ’๋งŒ ๊ฐ€๋Šฅ.
๊ทธ๋ž˜์„œ ๋ณ„๋„์˜ ํ…Œ์ด๋ธ”์„ ๋ฝ‘์•„์•ผ ํ•œ๋‹ค.

์˜ˆ๋ฅผ ๋“ค๋ฉด addressHistory๋กœ List๊ฐ€ ์žˆ๋‹ค๊ณ  ํ•œ๋‹ค๋ฉด ADDRESS ํ…Œ์ด๋ธ”์„ ๋”ฐ๋กœ ๋ฝ‘์•„์„œ Member_id, CITY, STREET, ZIPCODE ์ปฌ๋Ÿผ์„ ๋งŒ๋“ค์–ด์•ผ ํ•œ๋‹ค.
favoriteFoods : Set<String>
addressHistory : List<Address>

@ElementCollection
@CollectionTable(name = "FAVORITE_FOOD", joinColumns = @JoinColumn(name = "MEMBER_ID"))
@Column(name = "FOOD_NAME") // ๊ฐ’์ด String์œผ๋กœ ํ•˜๋‚˜๊ณ  Address ์ฒ˜๋Ÿผ ๋‚ด๊ฐ€ ์ •์˜ํ•œ ๊ฒƒ์ด ์•„๋‹ˆ๊ธฐ ๋•Œ๋ฌธ์— ์˜ˆ์™ธ์ ์œผ๋กœ ์ด๋ฆ„ ์„ค์ • ๊ฐ€๋Šฅ.
private Set<String> favoriteFoods = new HashSet<>();

@ElementCollection
@CollectionTable(name = "ADDRESS", joinColumns = @JoinColumn(name = "MEMBER_ID"))
private Set<Adress> addressHistory = new ArrayList<>();

@ElementCollection
ํ•ด๋‹น ํ•„๋“œ๊ฐ€ ์ปฌ๋ ‰์…˜ ๊ฐ์ฒด์ž„์„ JPA์—๊ฒŒ ์•Œ๋ ค์ฃผ๋Š” ์–ด๋…ธํ…Œ์ด์…˜
๊ฐ’ ํƒ€์ž… ์ปฌ๋ ‰์…˜์„ ๋งคํ•‘ํ•  ๋•Œ ์‚ฌ์šฉํ•œ๋‹ค.

โ— ์—ฐ๊ด€๋œ ๋ถ€๋ชจ Entity ํ•˜๋‚˜์—๋งŒ ์—ฐ๊ด€๋˜์–ด ๊ด€๋ฆฌ๋œ๋‹ค. (๋ถ€๋ชจ Entity์™€ ๋…๋ฆฝ์ ์œผ๋กœ ์‚ฌ์šฉ์ด ๋ถˆ๊ฐ€๋Šฅ)
โ— ํ•ญ์ƒ ๋ถ€๋ชจ์™€ ํ•จ๊ป˜ ์ €์žฅ๋˜๊ณ  ์‚ญ์ œ๋˜๋ฏ€๋กœ cascade ์˜ต์…˜์€ ์ œ๊ณตX
โ— ๋ถ€๋ชจ Entity Id์™€ ์ถ”๊ฐ€ ์ปฌ๋Ÿผ(basic or ์ž„๋ฒ ๋””๋“œ)์œผ๋กœ ๊ตฌ์„ฑ๋จ
โ— ๊ธฐ๋ณธ์ ์œผ๋กœ ์‹๋ณ„์ž ๊ฐœ๋…์ด ์—†์œผ๋ฏ€๋กœ ์ปฌ๋ ‰์…˜ ๊ฐ’ ๋ณ€๊ฒฝ ์‹œ, ์ „์ฒด ์‚ญ์ œ ํ›„ ์ƒˆ๋กœ ์ถ”๊ฐ€ํ•ด์•ผํ•œ๋‹ค.

@CollectionTable
๊ฐ’ ํƒ€์ž… ์ปฌ๋ ‰์…˜์„ ๋งคํ•‘ํ•  ํ…Œ์ด๋ธ”์— ๋Œ€ํ•œ ์ •๋ณด๋ฅผ ์ง€์ •ํ•˜๋Š” ์—ญํ• ์„ ์ˆ˜ํ–‰ํ•ฉ๋‹ˆ๋‹ค.



๊ฐ’ ํƒ€์ž…๋“ค์€ ๋ณ„๋„๋กœ persistํ•˜๊ฑฐ๋‚˜ ์—…๋ฐ์ดํŠธ ํ•  ๊ฒŒ ์—†๋‹ค. member์—์„œ ๊ฐ’์„ ๋ฐ”๊พธ๋ฉด ์ž๋™์œผ๋กœ ์—…๋ฐ์ดํŠธ ๋œ๋‹ค.
๊ฐ’ ํƒ€์ž… ์ปฌ๋ ‰์…˜์€ ์˜์†์„ฑ ์ „์ด(Cascade) + ๊ณ ์•„ ๊ฐ์ฒด ์ œ๊ฑฐ ๊ธฐ๋Šฅ์„ ํ•„์ˆ˜๋กœ ๊ฐ€์ง„๋‹ค๊ณ  ๋ณผ ์ˆ˜ ์žˆ๋‹ค
์ปฌ๋ ‰์…˜๋“ค์€ ์ง€์—ฐ ๋กœ๋”ฉ์ด๋‹ค.
์—”ํ‹ฐํ‹ฐ์™€ ๋‹ค๋ฅด๊ฒŒ ์‹๋ณ„์ž ๊ฐœ๋…์ด ์—†๊ณ  ๊ฐ’์€ ๋ณ€๊ฒฝํ•˜๋ฉด ์ถ”์ ์ด ์–ด๋ ต๋‹ค.

๊ฐ’ ํƒ€์ž… ์ปฌ๋ ‰์…˜์— ๋ณ€๊ฒฝ ์‚ฌํ•ญ์ด ๋ฐœ์ƒํ•˜๋ฉด, ์ฃผ์ธ ์—”ํ‹ฐํ‹ฐ์™€ ์—ฐ๊ด€๋œ ๋ชจ๋“  ๋ฐ์ดํ„ฐ๋ฅผ ์‚ญ์ œํ•˜๊ณ , ๊ฐ’ ํƒ€์ž… ์ปฌ๋ ‰์…˜์— ์žˆ๋Š” ํ˜„์žฌ ๊ฐ’์„ ๋ชจ๋‘ ๋‹ค์‹œ ์ €์žฅํ•œ๋‹ค.
๊ฐ’ ํƒ€์ž… ์ปฌ๋ ‰์…˜์„ ๋งคํ•‘ํ•˜๋Š” ํ…Œ์ด๋ธ”์€ ๋ชจ๋“  ์ปฌ๋Ÿผ์„ ๋ฌถ์–ด์„œ ๊ธฐ๋ณธ ํ‚ค๋ฅผ ๊ตฌ์„ฑํ•ด์•ผ ํ•œ๋‹ค.
โ— null ์ž…๋ ฅ๋„ ๋ถˆ๊ฐ€๋Šฅํ•˜๊ณ  ์ฃผ์˜ฅ ์ €์žฅ๋„ ๋ถˆ๊ฐ€๋Šฅํ•˜๋‹ค.



String์„ ์ˆ˜์ •ํ•  ๋•Œ๋Š” ๋ณ„ ๋‹ค๋ฅธ ๋ฐฉ๋ฒ• ์—†์ด ์ปฌ๋ ‰์…˜์„ ์‚ฌ์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•์œผ๋กœ ์ˆ˜์ •.

findMember.getFavoriteFoods().remove("์น˜ํ‚จ");
findMember.getFavoriteFoods().add("ํ•œ์‹");

address์˜ ๊ฒฝ์šฐ๋Š” Address๋กœ ์ œ๋„ˆ๋ฆญ์ด๊ธฐ ๋•Œ๋ฌธ์— ๋ถˆ๋ณ€ ๊ฐ์ฒด ํ•  ๋•Œ์ฒ˜๋Ÿผ ํ•˜๋ฉด ๋œ๋‹ค.

findMember.getFavoriteFoods().remove(new Address("old_1", "street", "1234"));
findMember.getFavoriteFoods().add(new Address("newCity1", "street", "1234"));

remove() ์ž์ฒด๊ฐ€ ๊ธฐ๋ณธ์ ์œผ๋กœ equals๋กœ ๋™์ž‘ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ๊ธฐ์กด์— ์žˆ๋Š” ์š”์†Œ๋ฅผ ์ฐพ๊ธฐ ์œ„ํ•ด์„œ๋Š” equals()๋ฅผ ๋™์ž‘ํ•ด ๊ฐ์ฒด์˜ ์˜ฌ๋ฐ”๋ฅธ ๋น„๊ต๊ฐ€ ํ•„์š”ํ•˜๋‹ค.
(hashcode ํ•„์š”)



๐Ÿท๏ธ ๋Œ€์•ˆ

โ— ์‹ค๋ฌด์—์„œ๋Š” ์ƒํ™ฉ์— ๋”ฐ๋ผ ๊ฐ’ ํƒ€์ž… ์ปฌ๋ ‰์…˜ ๋Œ€์‹ ์— ์ผ๋Œ€๋‹ค ๊ด€๊ณ„๋ฅผ ๊ณ ๋ ค

โ— ์ผ๋Œ€๋‹ค ๊ด€๊ณ„๋ฅผ ์œ„ํ•œ ์—”ํ‹ฐํ‹ฐ๋ฅผ ๋งŒ๋“ค๊ณ , ์—ฌ๊ธฐ์—์„œ ๊ฐ’ ํƒ€์ž…์„ ์‚ฌ์šฉ.
์ผ๋Œ€๋‹ค๋กœ ์ˆ˜์ • ์‹œ update ์ฟผ๋ฆฌ๊ฐ€ ๋‚˜๊ฐ€๋Š” ๊ฑด ์–ด์ฉ” ์ˆ˜ ์—†์Œ
->์ผ๋Œ€๋‹ค ๋‹จ๋ฐฉํ–ฅ ๋งคํ•‘์˜ ๊ฒฝ์šฐ ๋‹ค๋ฅธ ํ…Œ์ด๋ธ”์— ์™ธ๋ž˜ํ‚ค๊ฐ€ ์žˆ์–ด update ์ฟผ๋ฆฌ๊ฐ€ ๋‚˜๊ฐ.

โ— ์ง„์งœ ๋‹จ์ˆœํ•œ ๊ฑฐ ๋•Œ ๊ฐ’ ํƒ€์ž… ์‚ฌ์šฉํ•˜๊ณ  ๋‚˜๋จธ์ง€๋Š” ๊ทธ๋ƒฅ ์ผ๋Œ€๋‹ค ๊ด€๊ณ„๋กœ ์—”ํ‹ฐํ‹ฐ ๋งŒ๋“ ๋‹ค. (์ถ”์ ํ•  ํ•„์š”๋„ ์—†๊ณ  update(๊ฐ’์ด ๋ฐ”๋€œ) ๋„ ํ•„์š”์—†์„ ๋•Œ)
์˜ˆ๋ฅผ ๋“ค๋ฉด ์…€๋ ‰ํŠธ ๋ฐ•์Šค์ฒ˜๋Ÿผ.

โ— ์˜์†์„ฑ ์ „์ด + ๊ณ ์•„ ๊ฐ์ฒด ์ œ๊ฑฐ๋ฅผ ์‚ฌ์šฉํ•ด์„œ ๊ฐ’ ํƒ€์ž… ์ปฌ๋ ‰์…˜์ฒ˜๋Ÿผ ์‚ฌ์šฉ.

AddressEntity๋ฅผ ํ•˜๋‚˜ ๋” ์ƒ์„ฑ

@Entity
@Table(name = "ADDRESS")
public class AddressEntity{
	@Id @GeneratedValue
    private Long id;
    
    private Address address; // ๊ฐ’ ํƒ€์ž… ์ปฌ๋ ‰์…˜
    
    public AddressEntity(){}
    
    public AddressEntity(Address address){
    	this.address = address;
    }
    
    public AddressEntity(String city, String street, String zipcode){
    	this.address = new Address(city, street, zipcode);
	}
}

Member.class

@OneToMany(casecade = CascadeType.AlLL, orphanRemoval = true)
@JoinColumn(name = "MEMBER_ID")
private List<AddressEntity> addressHistory = new ArrayList<>();

@OneToMany, @ManyToOne ์œผ๋กœ ๊ธฐ๋ณธ ๋งคํ•‘ํ•ด์„œ ํ’€์–ด๋„ ๋˜๊ณ  ์ผ๋Œ€๋‹ค ๋‹จ๋ฐฉํ–ฅ ๋งคํ•‘์œผ๋กœ ํ•ด๋„ ๋œ๋‹ค.






โœ๏ธ JPQL ๋ฌธ๋ฒ•

select m from **Member** as m where m.**age** > 18
(์—”ํ‹ฐํ‹ฐ Member ์™€ ์†์„ฑ age๋Š” ๋Œ€์†Œ๋ฌธ์ž ๊ตฌ๋ถ„)
ํ…Œ์ด๋ธ” ์ด๋ฆ„์ด ์•„๋‹Œ ์—”ํ‹ฐํ‹ฐ ์ด๋ฆ„ ์‚ฌ์šฉ
๋ณ„์นญ(as m) ์€ ํ•„์ˆ˜๋‹ค. as๋Š” ์ƒ๋žต ๊ฐ€๋Šฅ

Member member = new Member();
member.setUsername("member1");
member.setAge(10);
em.persist(member);

TypedQuery<Member> query = em.createQuery("select m from Member m", Member.class);

//๋ฐ˜ํ™˜ ํƒ€์ž…์ด ๋ช…ํ™•ํ•  ๋•Œ๋Š” TypedQuery๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค.
/*List<Member> resultList = query.getResultList(); //์ปฌ๋ ‰์…˜์ด ๋ฐ˜ํ™˜๋จ.

for (Member member1 : resultList) {
	System.out.println("member1 = " + member1);
}*/

Member singleResult = query.getSingleResult();
System.out.println("singleResult = " + singleResult);

query.getResultList()
๊ฒฐ๊ณผ๊ฐ€ 2๊ฐœ ์ด์ƒ์ผ ๋•Œ ๋ฆฌ์ŠคํŠธ ๋ฐ˜ํ™˜ , ๊ฒฐ๊ณผ๊ฐ€ ์—†์œผ๋ฉด ๋นˆ ๋ฆฌ์ŠคํŠธ ๋ฐ˜ํ™˜(nullPointerException ๊ฑฑ์ • ์—†์Œ)

query.getSingleResult()
๊ฒฐ๊ณผ๊ฐ€ ์ •ํ™•ํ•˜๊ฒŒ ํ•œ ๊ฐœ ๋‚˜์™€์•ผ ํ•œ๋‹ค.
๊ฒฐ๊ณผ๊ฐ€ ์—†์œผ๋ฉด : javax.persistence.NoResultException

๊ฒฐ๊ณผ๊ฐ€ ๋‘˜ ์ด์ƒ์ด๋ฉด : javax.persistence.NonUniqueResultException ๋ฐœ์ƒ

/*TypedQuery<Member> query = em.createQuery("select m from Member m where m.username = :username", Member.class);
query.setParameter("username", "member1");*/

//๋ฐ˜ํ™˜ ํƒ€์ž…์ด ๋ช…ํ™•ํ•  ๋•Œ๋Š” TypedQuery๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค.

//Member singleResult = query.getSingleResult();

//System.out.println("singleResult = " + singleResult.getUsername());

//์œ„ ์ฒ˜๋Ÿผ ์“ฐ์ง€ ์•Š๊ณ  ๋ฐ‘์— ์ฒ˜๋Ÿผ ๊ฐ„๋‹จํ•˜๊ฒŒ ์‚ฌ์šฉํ•จ
Member result = em.createQuery("select m from Member m where m.username = :username", Member.class)
	.setParameter("username", "member1")
    .getSingleResult(); //์ด๋ฆ„ ๊ธฐ์ค€ ํŒŒ๋ผ๋ฏธํ„ฐ ๋ฐ”์ธ๋”ฉ

์œ„์น˜ ๊ธฐ์ค€ ๋ฐ”์ธ๋”ฉ์€ ๋˜๋„๋ก ์“ฐ์ง€ ์•Š๋Š” ๊ฒƒ์ด ์ข‹์Œ (์ˆœ์„œ ๋ฐ”๋€” ์ˆ˜ ์žˆ์Œ)






โœ๏ธ ํ”„๋กœ์ ์…˜

SELECT ์ ˆ์— ์กฐํšŒํ•  ๋Œ€์ƒ์„ ์ง€์ •ํ•˜๋Š” ๊ฒƒ
SELECT m FROM Member m -> ์—”ํ‹ฐํ‹ฐ ํ”„๋กœ์ ์…˜
SELECT m.team FROM Member m -> ์—”ํ‹ฐํ‹ฐ ํ”„๋กœ์ ์…˜ (๋ช…์‹œ์ ์œผ๋กœ join ๋„ฃ์–ด์ฃผ๋Š” ๊ฒƒ์ด ์ข‹์Œ)

SELECT m.address FROM Member m -> ์ž„๋ฒ ๋””๋“œ ํƒ€์ž… ํ”„๋กœ์ ์…˜
SELECT m.username, m.age FROM Member m -> ์Šค์นผ๋ผ ํƒ€์ž… ํ”„๋กœ์ ์…˜

DISTINCT๋กœ ์ค‘๋ณต ์ œ๊ฑฐ



๐Ÿท๏ธ ํ”„๋กœ์ ์…˜ ์—ฌ๋Ÿฌ ๊ฐ’ ์กฐํšŒ

  1. Query ํƒ€์ž…์œผ๋กœ ์กฐํšŒ
  2. Object[] ํƒ€์ž…์œผ๋กœ ์กฐํšŒ
  3. new ๋ช…๋ น์–ด๋กœ ์กฐํšŒ
    โ— ๋‹จ์ˆœ ๊ฐ’์„ DTO๋กœ ๋ฐ”๋กœ ์กฐํšŒ
List<MemberDTO> result = em.createQuery("select new jpql.MemberDTO(m.username, m.age) from Member m", MemberDTO.class)
                    .getResultList
  
MemberDTO memberDTO = result.get(0);
System.out.println("memberDTO = " + memberDTO.getUsername());
System.out.println("memberDTO = " + memberDTO.getAge());

โ—ํŒจํ‚ค์ง€ ๋ช…์„ ํฌํ•จํ•œ ์ „์ฒด ํด๋ž˜์Šค๋ช… ์ž…๋ ฅ
โ—์ˆœ์„œ์™€ ํƒ€์ž…์ด ์ผ์น˜ํ•˜๋Š” ์ƒ์„ฑ์ž ํ•„์š”



โœ๏ธ ํŽ˜์ด์ง• API

List<Member> result = em.createQuery("select m from Member m order by m.age desc", Member.class)
		.setFirstResult(1)
    	.setMaxResults(10)
    	.getResultList();

.setFirstResult(1)
์กฐํšŒ ์‹œ์ž‘ ์œ„์น˜ (0๋ถ€ํ„ฐ ์‹œ์ž‘)

.setMaxResults(10)
์กฐํšŒํ•  ๋ฐ์ดํ„ฐ ์ˆ˜

์œ„ 2๊ฐœ๋งŒ ์ฑ™๊ฒจ์„œ ๋„ฃ์–ด์ฃผ๋ฉด ?์— ์ถ”์ƒ์ ์œผ๋กœ ์ƒ๊ฐํ–ˆ๋˜ ๊ฐ’์„ ์•Œ์•„์„œ ๋‹ค ๋„ฃ์–ด์ค€๋‹ค.
->์šฐ๋ฆฌ๋Š” ์ธ๋ฑ์Šค, ๋ช‡ ๊ฐœ ๊ฐ€์ ธ์˜ฌ์ง€ ์ด๋Ÿฐ ๊ฒƒ๋งŒ ์‹ ๊ฒฝ์“ฐ๋ฉด ๋จ.






โœ๏ธ JOIN: ํ•œ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ๋‚ด์˜ ์—ฌ๋Ÿฌ ํ…Œ์ด๋ธ”์˜ ๋ ˆ์ฝ”๋“œ๋ฅผ ์กฐํ•ฉํ•˜์—ฌ ํ•˜๋‚˜์˜ ์—ด๋กœ ํ‘œํ˜„ํ•œ ๊ฒƒ์ด๋‹ค.

๋‚ด๋ถ€ ์กฐ์ธ: SELECT ~~ [INNER] JOIN m.team t
์™ธ๋ถ€ ์กฐ์ธ: SELECT ~~ LEFT [OUTER] JOIN m.team t

๋‚ด๋ถ€ ์กฐ์ธ๊ณผ ์™ธ๋ถ€ ์กฐ์ธ ์ฐจ์ด
๋‚ด๋ถ€๋Š” ํ‚ค ๊ฐ’์ด ์žˆ๋Š” ํ…Œ์ด๋ธ”์˜ ์นผ๋Ÿผ ๊ฐ’์„ ๋น„๊ตํ•ด์„œ ๋งž๋Š” ๊ฐ’์„ ๊ฐ€์ ธ์˜ค๋Š” ๊ฒƒ์ด๋‹ค.
ํ•œ ๋งˆ๋””๋กœ ์„œ๋กœ ๊ด€๋ จ๋œ ๋‚ด์šฉ์„ ๊ฒ€์ƒ‰ํ•ด ๊ฐ€์ ธ์˜ค๋Š” ๋ฐฉ๋ฒ•์ด๋ผ ์ƒ๊ฐ
์™ธ๋ถ€๋Š” ์—ฌ๋Ÿฌ ํ…Œ์ด๋ธ” ์ค‘ ํ•œ ํ…Œ์ด๋ธ”์—๋งŒ ๋ฐ์ดํ„ฐ๊ฐ€ ์žˆ๊ณ  ๋‹ค๋ฅธ ์ชฝ์—๋Š” ์—†๋Š” ๊ฒฝ์šฐ, ๋ฐ์ดํ„ฐ๊ฐ€ ์žˆ๋Š” ํ…Œ์ด๋ธ”์˜ ๋‚ด์šฉ์„ ์ „๋ถ€ ์ถœ๋ ฅํ•˜๋Š” ๋ฐฉ๋ฒ•์ด๋‹ค.






โœ๏ธ ์กฐ์ธ - ON์ ˆ

  1. ์กฐ์ธํ•  ๋•Œ ๋ฏธ๋ฆฌ ๋Œ€์ƒ์„ ํ•„ํ„ฐ๋ง
  2. ์—ฐ๊ด€๊ด€๊ณ„ ์—†๋Š” ์—”ํ‹ฐํ‹ฐ ์™ธ๋ถ€ ์กฐ์ธ
String query = "select m from Member m left join Team t on m.username = t.name";

๐Ÿท๏ธ ์„œ๋ธŒ ์ฟผ๋ฆฌ

WHERE, HAVING ์ ˆ์—์„œ๋งŒ ์„œ๋ธŒ ์ฟผ๋ฆฌ ์‚ฌ์šฉ ๊ฐ€๋Šฅ
SELECT ์ ˆ๋„ ๊ฐ€๋Šฅ
FROM ์ ˆ์˜ ์„œ๋ธŒ ์ฟผ๋ฆฌ๋Š” ํ˜„์žฌ JPQL์—์„œ ๋ถˆ๊ฐ€๋Šฅ
-> ์กฐ์ธ์œผ๋กœ ํ’€ ์ˆ˜ ์žˆ์œผ๋ฉด ํ’€์–ด์„œ ํ•ด๊ฒฐํ•˜๋„๋ก

//ํŒจํ‚ค์ง€ ๋ช…๊นŒ์ง€ ๋„ฃ์–ด์•ผ ํ•จ. -> ADMIN ํƒ€์ž…์˜ ์œ ์ €๋งŒ ์กฐํšŒํ•จ
String query = "select m.username, 'HELLO', true From Member m " +
                    "where m.type = jpql.MemberType.USER"; 


List<Member> result = em.createQuery(query)
                    .getResultList();


๐Ÿท๏ธ CASE ์‹

String query = "select " + 
	"case when m.age <= 10 then 'ํ•™์ƒ์š”๊ธˆ' " +
    "when m.age >= 60 then '๊ฒฝ๋กœ์š”๊ธˆ' " +
    "else '์ผ๋ฐ˜์š”๊ธˆ' " +
    "end " +
    "from Member m";

List<String> result = em.createQuery(query, String.class)
	.getResultList();

coalesce : ํ•˜๋‚˜์”ฉ ์กฐํšŒํ•ด์„œ null์ด ์•„๋‹ˆ๋ฉด ๋ฐ˜ํ™˜



String query = "select coalesce(m.username, '์ด๋ฆ„ ์—†๋Š” ํšŒ์›') as username " + 
	"from Member m ";

List<String> result = em.createQuery(query, String.class)
	.getResultList();
// ๊ฒฐ๊ณผ๋Š” s = ์ด๋ฆ„ ์—†๋Š” ํšŒ์›

nullif: ๋‘ ๊ฐ’์ด ๊ฐ™์œผ๋ฉด null๋ฐ˜ํ™˜, ๋‹ค๋ฅด๋ฉด ์ฒซ ๋ฒˆ์งธ ๊ฐ’ ๋ฐ˜ํ™˜

String query = "select nullif(m.username, '๊ด€๋ฆฌ์ž') as username " +
	"from Member m ";

List<String> result = em.createQuery(query, String.class)
	.getResultList();
//s = null





โœ๏ธ JPQL ๊ธฐ๋ณธ ํ•จ์ˆ˜

  • CONCAT
    • ๋ฌธ์ž ๋”ํ•ด์คŒ
  • SUBSTRING
    • ~๋ถ€ํ„ฐ ~๊นŒ์ง€ ๋ฌธ์ž์—ด ๋ฝ‘์•„๋ƒ„
  • TRIM
    • ๊ณต๋ฐฑ ์ œ๊ฑฐ
  • LOWER, UPPER
    • ๋Œ€์†Œ๋ฌธ์ž
  • LENGTH
    ๋ฌธ์ž์—ด๊ธธ์ด
  • LOCATE
    • ์œ„์น˜ ์ฐพ์•„์คŒ -> locate('de', 'abcdegf')
    • s = 4๊ฐ€ ๋‚˜์˜ด
  • ABS, SQRT, MOD
    • ์ ˆ๋Œ€๊ฐ’, ,
  • SIZE
    • size๋Š” ์ปฌ๋ ‰์…˜ ํฌ๊ธฐ๋ฅผ ๊ตฌํ•จ.
      ํ•œ ์ค„๋กœ ์ถœ๋ ฅ





โœ๏ธ ๊ฒฝ๋กœ ํ‘œํ˜„์‹

.(์ )์„ ์ฐ์–ด ๊ฐ์ฒด ๊ทธ๋ž˜ํ”„๋ฅผ ํƒ์ƒ‰ํ•˜๋Š” ๊ฒƒ
select m.username -> ์ƒํƒœ ํ•„๋“œ
from Member m join m.team t -> ๋‹จ์ผ ๊ฐ’ ์—ฐ๊ด€ ํ•„๋“œ
m.orders o -> ์ปฌ๋ ‰์…˜ ๊ฐ’ ์—ฐ๊ด€ ํ•„๋“œ

ํ•„๋“œ 3๊ฐ€์ง€ (๊ถŒ์žฅX -> ๋ฌต์‹œ์  ์กฐ์ธ์€ ์œ„ํ—˜ํ•˜๋‹ค.)
์ƒํƒœ ํ•„๋“œ : ๋‹จ์ˆœํžˆ ๊ฐ’์„ ์ €์žฅํ•˜๊ธฐ ์œ„ํ•œ ํ•„๋“œ, ๊ฒฝ๋กœ ํƒ์ƒ‰์˜ ๋์œผ๋กœ ํƒ์ƒ‰์ด ๋ถˆ๊ฐ€๋Šฅํ•˜๋‹ค.
ex) m.username ์ด๋ผํ•  ๋•Œ m.username.~~ ๋กœ ๋” ํƒ์ƒ‰์ด ๋ถˆ๊ฐ€๋Šฅํ•˜๋‹ค.

์—ฐ๊ด€ ํ•„๋“œ : ์—ฐ๊ด€๊ด€๊ณ„๋ฅผ ์œ„ํ•œ ํ•„๋“œ
โ— ๋‹จ์ผ ๊ฐ’ : @ManyToOne, @OneToOne, ๋Œ€์ƒ์ด ์—”ํ‹ฐํ‹ฐ (ex m.team)
๋ฌต์‹œ์  ๋‚ด๋ถ€ ์กฐ์ธ ๋ฐœ์ƒ, ํƒ์ƒ‰O
๋ฌต์‹œ์  ๋‚ด๋ถ€ ์กฐ์ธ ๋ฐœ์ƒ -> ๊ฐ์ฒด ์ž…์žฅ์—์„œ๋Š” m.team ์ด๋Ÿฐ ์‹์œผ๋กœ ํ•˜๋ฉด ๋˜์ง€๋งŒ DB์ž…์žฅ์—์„œ๋Š” ์กฐ์ธ์ด ์ผ์–ด๋‚˜์•ผ ํ•œ๋‹ค.

์›ฌ๋งŒํ•˜๋ฉด ๋ฌต์‹œ์  ๋‚ด๋ถ€ ์กฐ์ธ์€ ์‚ฌ์šฉX
โ— ์ปฌ๋ ‰์…˜ ๊ฐ’ : @OneToMany, @ManyToMany, ๋Œ€์ƒ์ด ์ปฌ๋ ‰์…˜ (ex m.orders)
๋ฌต์‹œ์  ๋‚ด๋ถ€ ์กฐ์ธ ๋ฐœ์ƒ, ํƒ์ƒ‰X

๋ช…์‹œ์  ์กฐ์ธ join ํ‚ค์›Œ๋“œ๋ฅผ ์ง์ ‘ ์‚ฌ์šฉํ•œ๋‹ค. (์ด๊ฑธ ์‚ฌ์šฉ ๊ถŒ์žฅ)
ex) select m from Member m join m.team t






โœ๏ธ ํŽ˜์น˜ ์กฐ์ธ(fetch join) ๋งค์šฐ ์ค‘์š”

JPQL์—์„œ ์„ฑ๋Šฅ ์ตœ์ ํ™”๋ฅผ ์œ„ํ•ด ์ œ๊ณตํ•˜๋Š” ๊ธฐ๋Šฅ
์—ฐ๊ด€๋œ ์—”ํ‹ฐํ‹ฐ๋‚˜ ์ปฌ๋ ‰์…˜์„ SQL๋กœ ํ•œ ๋ฒˆ์— ํ•จ๊ป˜ ์กฐํšŒํ•˜๋Š” ๊ธฐ๋Šฅ
ex) ํšŒ์›์„ ์กฐํšŒํ•˜๊ณ  ์‹ถ์€๋ฐ ํšŒ์›์„ ์กฐํšŒํ•˜๋ฉด์„œ ์—ฐ๊ด€๋œ ํŒ€๋„ ํ•จ๊ป˜ ์กฐํšŒ๋œ๋‹ค.(SQL ํ•œ ๋ฒˆ์—)
๊ทธ๋Ÿฌ๋ฉด select m from Member m join fetch m.team ํ•˜๋ฉด ๋œ๋‹ค.
SQL ์—์„œ๋Š”
SELECT M.*, T.* FROM MEMBER M INNER JOIN TEAM T ON M.TEAM_ID = T.ID
์ฟผ๋ฆฌ๋กœ ๋‚ด๊ฐ€ ์›ํ•˜๋Š”๋Œ€๋กœ ์–ด๋–ค ๊ฐ์ฒด ๊ทธ๋ž˜ํ”„๋ฅผ ํ•œ ๋ฒˆ์— ์กฐํšŒํ•  ๊ฑฐ๋ผ๋Š” ๊ฒƒ์„ ์ง์ ‘ ๋ช…์‹œ์ ์œผ๋กœ, ๋™์ ์œผ๋กœ ๋‚˜ํƒ€๋‚ธ๋‹ค.






โœ๏ธ @ManyToOne ํŽ˜์น˜์กฐ์ธ

Team teamA = new Team();
teamA.setName("ํŒ€A");
em.persist(teamA);

Team teamB = new Team();
teamB.setName("ํŒ€B");
em.persist(teamB);

Member member1 = new Member();
member1.setUsername("ํšŒ์› 1");
member1.setTeam(teamA);
em.persist(member1);

Member member2 = new Member();
member2.setUsername("ํšŒ์› 2");
member2.setTeam(teamA); //์†Œ์†๋œ ํŒ€
em.persist(member2);

Member member3 = new Member();
member3.setUsername("ํšŒ์› 3");
member3.setTeam(teamB); //์†Œ์†๋œ ํŒ€
em.persist(member3);
  
String query = "select m From Member m ";
List<Member> result = em.createQuery(query, Member.class)
	.getResultList();

for (Member member : result) {
	System.out.println("member = " + member.getUsername() + ", " + member.getTeam().getName());
            
}
tx.commit();

ํšŒ์›1, ํŒ€A๋ฅผ SQL ์ฟผ๋ฆฌ๋กœ ๊ฐ€์ €์˜ด -> ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ์— ์—†๊ธฐ ๋•Œ๋ฌธ์— SQL.

ํšŒ์›2, ํŒ€A(1์ฐจ ์บ์‹œ)
ํšŒ์›3, ํŒ€B(SQL) ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ์— ์—†๊ธฐ ๋•Œ๋ฌธ์— SQL ์ฟผ๋ฆฌ ๋‚ ๋ ค์„œ ์˜์†์„ฑ์— ์˜ฌ๋ฆฌ๊ณ  ๊ฒฐ๊ณผ๋ฅผ ๋ฐ˜ํ™˜.

์ด๋Ÿฌ๋ฉด ํšŒ์› 100๋ช…์ด ๋‹ค ๋‹ค๋ฅธ ํŒ€์ด๋ฉด ์ฟผ๋ฆฌ๊ฐ€ 100 + 1 (N+1) ๋ฒˆ ๋‚˜๊ฐ„๋‹ค.
๊ทธ๋ž˜์„œ ์ด ๋ฌธ์ œ๋Š” ํŽ˜์น˜ ์กฐ์ธ์œผ๋กœ ํ‘ผ๋‹ค.


String query = "select m From Member m join fetch m.team";

์ด๋•Œ get.Team()์€ ํ”„๋ก์‹œ๊ฐ€ ์•„๋‹ˆ๋‹ค.
์ด๋ฏธ member์™€ team์˜ ๋ฐ์ดํ„ฐ๋ฅผ ์กฐ์ธํ•ด์„œ ๋‹ค ๊ฐ€์ ธ์™”๊ณ  ์ฟผ๋ฆฌ๊ฐ€ ๋‚ ๋ผ๊ฐ€์„œ result์— ๋‹ด๊ธฐ๋Š” ์‹œ์ ์— Team์€ ํ”„๋ก์‹œ๊ฐ€ ์•„๋‹Œ ์‹ค์ œ ๋ฐ์ดํ„ฐ๊ฐ€ ๋‹ด๊ธฐ๊ฒŒ ๋œ๋‹ค.






โœ๏ธ ์ปฌ๋ ‰์…˜ ํŽ˜์น˜ ์กฐ์ธ (@ManyToOne ๊ณผ ๋ฐ˜๋Œ€๋กœ Team ์œผ๋กœ๋ถ€ํ„ฐ ์กฐ์ธ)

String query = "select t From Team t join fetch t.members";

List<Team> result = em.createQuery(query, Team.class)
                    .getResultList();

for (Team team : result) {
	System.out.println("Team = " + team.getName() + "| members : " + team.getMembers().size());
}

tx.commit();

Team = ํŒ€A | members : 2
Team = ํŒ€A | members : 2
Team = ํŒ€B | members : 1
ํŒ€A์— ํšŒ์›์ด 2๋ช… ์žˆ๊ธฐ ๋•Œ๋ฌธ์— 2๋ฒˆ ์ถœ๋ ฅ์ด ๋œ ๊ฒƒ์ด๋‹ค.

join fetch๋ฅผ ํ•˜๊ฒŒ ๋˜๋ฉด ์ผ๋Œ€๋‹ค ๊ด€๊ณ„ ๋•Œ๋ฌธ์— ๋ปฅํŠ€๊ธฐ ๋˜์„œ result.size() ๋ฅผ ์ถœ๋ ฅํ•˜๋ฉด 3์ด ๋œ๋‹ค
-> (๋‹ค๋Œ€์ผ์€ ๋ปฅํŠ€๊ธฐ ์•ˆ๋จ.)



ํ•ด๊ฒฐ -> select distinct t
SQL์— distinct ์ถ”๊ฐ€ํ•ด๋„ ๋ฐ์ดํ„ฐ๊ฐ€ ๋‹ค๋ฅด๋ฉด SQL ๊ฒฐ๊ณผ์—์„œ ์ค‘๋ณต ์ œ๊ฑฐ๊ฐ€ ์‹คํŒจํ•œ๋‹ค.
๊ทธ๋ž˜์„œ JPA์—์„œ distinct๊ฐ€ ์ถ”๊ฐ€๋กœ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์—์„œ ์ค‘๋ณต ์ œ๊ฑฐ๋ฅผ ์‹œ๋„ํ•œ๋‹ค.
๊ทธ๋Ÿฌ๋ฉด์„œ ๊ฐ™์€ ์‹๋ณ„์ž๋ฅผ ๊ฐ€์ง„ Team ์—”ํ‹ฐํ‹ฐ๋ฅผ ์ œ๊ฑฐํ•œ๋‹ค. -> ์ค‘๋ณต์ด ์ œ๊ฑฐ๋œ team ๊ฒฐ๊ณผ ๋ฆฌ์ŠคํŠธ๋ฅผ ๋ฐ˜ํ™˜ํ•œ๋‹ค.

โœ๏ธ ํŽ˜์น˜ ์กฐ์ธ ํ•œ๊ณ„

  • ํŽ˜์น˜ ์กฐ์ธ ๋Œ€์ƒ์—๋Š” ๋ณ„์นญ(as) ๋ฅผ ์ค„ ์ˆ˜ ์—†๋‹ค. (์›์น™์ ์œผ๋กœ)
  • ๋‘˜ ์ด์ƒ์˜ ์ปฌ๋ ‰์…˜์€ ํŽ˜์น˜ ์กฐ์ธ ํ•  ์ˆ˜ ์—†๋‹ค.
  • ์ปฌ๋ ‰์…˜์„ ํŽ˜์น˜ ์กฐ์ธํ•˜๋ฉด ํŽ˜์ด์ง• API(setFirstResult, setMaxResults)๋ฅผ ํ•  ์ˆ˜ ์—†๋‹ค.

โ— ์ผ๋Œ€์ผ, ๋‹ค๋Œ€์ผ ๊ฐ™์€ ๋‹จ์ผ ๊ฐ’ ์—ฐ๊ด€ ํ•„๋“œ๋“ค์€ ํŽ˜์น˜ ์กฐ์ธํ•ด๋„ ํŽ˜์ด์ง• ๊ฐ€๋Šฅํ•˜๋‹ค.
์ผ๋Œ€๋‹ค ๊ด€๊ณ„์ธ ์ปฌ๋ ‰์…˜์—์„œ๋Š” ๋ฐ์ดํ„ฐ ๋ปฅํŠ€๊ธฐ๊ฐ€ ๋˜๊ธฐ ๋•Œ๋ฌธ์— ์‚ฌ์šฉํ•˜๋ฉด ์œ„ํ—˜ํ•œ ๊ฒƒ์ด๋‹ค.



ex) TEAM์—์„œ ํŒ€A๋ฅผ ์กฐํšŒํ•  ๋•Œ MEMBER๊ฐ€ 2๋ช… ์กฐํšŒ๊ฐ€ ๋œ๋‹ค๊ณ  ํ–ˆ์„ ๋•Œ ํŽ˜์ด์ง€ ์‚ฌ์ด์ฆˆ 1์— ๋ฐ์ดํ„ฐ๋ฅผ ํ•œ ๊ฑด๋งŒ ๊ฐ€์ ธ์˜จ๋‹ค๊ณ  ํ•œ๋‹ค๋ฉด ํŒ€A๋Š” ํšŒ์› ํ•˜๋‚˜๋งŒ ๊ฐ€์ง€๊ณ  ์žˆ๋‹ค๋Š” ์‹์ด ๋˜์–ด ๋ฒ„๋ฆฐ๋‹ค.


๐Ÿ”ฅ ๋ฌธ์ œ ํ•ด๊ฒฐ

  • ์ผ๋Œ€๋‹ค๊ฐ€ ์•„๋‹Œ "๋‹ค๋Œ€์ผ"์˜ ํ˜•ํƒœ๋กœ ์ฟผ๋ฆฌ๋ฅผ ์ˆ˜์ •ํ•ด์ค€๋‹ค.
  • N+1 ๋ฌธ์ œ ํ•ด๊ฒฐ์—๋Š” ํŽ˜์น˜ ์กฐ์ธ๋„ ์žˆ์ง€๋งŒ ์ปฌ๋ ‰์…˜์€ ํ•ด๊ฒฐ ๋ถˆ๊ฐ€๋Šฅํ•˜๋ฏ€๋กœ BatchSize๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค.
@BatchSize(size = 100)
@OneToMany(mappedBy = "team")
private List<Member> getMembers() {
	return members;
}

์ด๋Ÿฐ ์‹์œผ๋กœ ์“ธ ์ˆ˜ ์žˆ์ง€๋งŒ ๊ธ€๋กœ๋ฒŒ ์„ธํŒ…์œผ๋กœ ๊ฐ€์ ธ๊ฐ€๋„ ๋ฌด๊ด€(์‹ค๋ฌด์—์„œ๋Š” ๊ธ€๋กœ๋ฒŒ ์„ธํŒ…์œผ๋กœ ๊น”๊ณ  ๊ฐ)

persistence.xml ์—์„œ <property name="hibernate.default_batch_fetch_size" value="100" />

๊ทธ๋Ÿฌ๋ฉด ์ฟผ๋ฆฌ๊ฐ€ N+1์ด ์•„๋‹Œ ํ…Œ์ด๋ธ” ์ˆ˜๋งŒํผ ๋”ฑ ๋งž์ถฐ์„œ ๊ฐ€์ ธ๊ฐ€๊ฒŒ ๋จ

  1. ์—”ํ‹ฐํ‹ฐ์— ์ง์ ‘ ์ ์šฉํ•˜๋Š” ๊ธ€๋กœ๋ฒŒ ๋กœ๋”ฉ ์ „๋žต๋ณด๋‹ค ์šฐ์„ ์‹œ ๋œ๋‹ค.
    @OneToMany(fetch = FetchType.LAZY) => ๊ธ€๋กœ๋ฒŒ ์ „๋žต
  2. ์‹ค๋ฌด์—์„œ ๊ธ€๋กœ๋ฒŒ ๋กœ๋”ฉ ์ „๋žต์€ ๋ชจ๋‘ ์ง€์—ฐ ๋กœ๋”ฉ์œผ๋กœ ํ•œ๋‹ค.
  3. ์ตœ์ ํ™•๊ฐ€ ํ•„์š”ํ•œ ๊ณณ์—๋งŒ ํŽ˜์น˜ ์กฐ์ธ์„ ์ ์šฉํ•œ๋‹ค.

์—ฌ๋Ÿฌ ํ…Œ์ด๋ธ”์„ ์กฐ์ธํ•ด์„œ ์—”ํ‹ฐํ‹ฐ๊ฐ€ ๊ฐ€์ง„ ๋ชจ์–‘์ด ์•„๋‹Œ ์ „ํ˜€ ๋‹ค๋ฅธ ๊ฒฐ๊ณผ๋ฅผ ๋‚ด์•ผํ•œ๋‹ค๋ฉด ํŽ˜์น˜ ์กฐ์ธ ๋ณด๋‹ค๋Š” ์ผ๋ฐ˜ ์กฐ์ธ์„ ์‚ฌ์šฉํ•˜๊ณ  ํ•„์š”ํ•œ ๋ฐ์ดํ„ฐ๋“ค๋งŒ ์กฐํšŒํ•ด์„œ DTO๋กœ ๋ฐ˜ํ™˜ํ•˜๋Š” ๊ฒƒ์ด ํšจ๊ณผ์ ์ด๋‹ค.



โ— 3๊ฐ€์ง€ ๋ฐฉ๋ฒ•์ด ์žˆ๋‹ค.
1. ์—”ํ‹ฐํ‹ฐ๋“ค์„ ํŽ˜์น˜ ์กฐ์ธ ์จ์„œ ์—”ํ‹ฐํ‹ฐ๋“ค์„ ์กฐํšŒํ•ด ์˜จ๋‹ค.
2. ํŽ˜์น˜ ์กฐ์ธ ํ•ด์„œ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์—์„œ DTO๋กœ ๋ฐ”๊ฟ”์„œ ํ™”๋ฉด์— ๋ฐ˜ํ™˜ํ•œ๋‹ค.
3. ์ฒ˜์Œ JPQL ์งค ๋•Œ๋ถ€ํ„ฐ ์•„์˜ˆ new operation์œผ๋กœ DTO๋กœ ์Šค์œ„์นญํ•ด์„œ ๊ฐ€์ ธ์˜จ๋‹ค.






โœ๏ธ ์—”ํ‹ฐํ‹ฐ ์ง์ ‘ ์‚ฌ์šฉ

JPQL์—์„œ ์—”ํ‹ฐํ‹ฐ๋ฅผ ์ง์ ‘ ์‚ฌ์šฉํ•˜๋ฉด SQL์—์„œ ํ•ด๋‹น ์—”ํ‹ฐํ‹ฐ์˜ ๊ธฐ๋ณธ ํ‚ค ๊ฐ’์„ ์‚ฌ์šฉ
์ฆ‰ select count(m.id) ๊ฐ€ ์•„๋‹Œ count(m) ์„ ์‚ฌ์šฉํ•จ (๋‘˜์ด ๊ฒฐ๊ณผ๊ฐ€ ๊ฐ™์Œ)
ํ•ด๋‹น ์—”ํ‹ฐํ‹ฐ์˜ ๊ธฐ๋ณธ ํ‚ค ๊ฐ’์„ ์‚ฌ์šฉํ•˜๊ธฐ ๋•Œ๋ฌธ์—

์—”ํ‹ฐํ‹ฐ ์ง์ ‘ ์‚ฌ์šฉ -๊ธฐ๋ณธํ‚ค

String query = "select m From Member m where m.id = :memberId";
Member findMember = em.createQuery(query, Member.class)
		.setParameter("memberId", member1.getId())
        .getSingleResult();
        
System.out.println("findMember = " + findMember);

๊ฒฐ๊ณผ

where ember0_. id=?
findMember = Member{id=3, username='ํšŒ์›1', age=0}


์—”ํ‹ฐํ‹ฐ ์ง์ ‘ ์‚ฌ์šฉ -์™ธ๋ž˜ํ‚ค

String query = "select m From Member m where m.team = :team";

List<Member> members = em.createQuery(query, Member.class)
		.setParameter("team", teamA)
        .getResultList();
for (Member member : members) {
	System.out.println("member = " + member);
}

๊ฒฐ๊ณผ

where member0_.TEAM_ID=?
member = Member{id=3, username='ํšŒ์› 1', age=0}
member = Member{id=4, username='ํšŒ์› 2', age=0}

Named ์ฟผ๋ฆฌ(@Entity ๋ฐ‘์— ์”€)

  • ๋ฏธ๋ฆฌ ์ •์˜ํ•ด์„œ ์ฟผ๋ฆฌ์— ์ด๋ฆ„์„ ๋ถ€์—ฌ -> @NamedQuery


์ •์  ์ฟผ๋ฆฌ๋งŒ ๊ฐ€๋Šฅ
๋งค์šฐ ํฐ ์žฅ์  2๊ฐ€์ง€
โ— ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ๋กœ๋”ฉ ์‹œ์ ์— ์ดˆ๊ธฐํ™” ํ›„ ์žฌ์‚ฌ์šฉ -> ๋ณ€ํ•˜์ง€ ์•Š๋Š” ์ •์ ์ฟผ๋ฆฌ๋ฅผ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ๋กœ๋”ฉ ์‹œ์ ์— SQL๋กœ ํŒŒ์‹ฑํ•œ๋‹ค.

โ— ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ๋กœ๋”ฉ ์‹œ์ ์— ์ฟผ๋ฆฌ๋ฅผ ๊ฒ€์ฆ -> ์ฆ‰ query ๋ฌธ๋ฒ•์ด๋‚˜ ๋ฌธ์ž๊ฐ€ ๋งž๊ฒŒ ์ž…๋ ฅ์ด ๋˜์—ˆ๋Š”์ง€ ๊ฒ€์ฆ์„ ํ•œ๋‹ค.






โœ๏ธ ๋ฒŒํฌ ์—ฐ์‚ฐ

SQL์˜ UPDATE, DELETE์™€ ๊ฐ™๋‹ค๊ณ  ๋ณด๋ฉด ๋จ
์˜์†์„ฑ ์ปจํ…์ŠคํŠธ๋ฅผ ๋ฌด์‹œํ•˜๊ณ  ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์— ์ง์ ‘ ์ฟผ๋ฆฌ

2 ๊ฐ€์ง€ ๋ฐฉ๋ฒ• ์ค‘ ์„ ํƒ
โ— ๋ฒŒํฌ ์—ฐ์‚ฐ์„ ๋จผ์ € ์ˆ˜ํ–‰
โ— ๋ฒŒํฌ ์—ฐ์‚ฐ ์ˆ˜ํ–‰ ํ›„ ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ ์ดˆ๊ธฐํ™”(๊ถŒ์žฅ)

int resultCount = em.createQuery("update Member m set m.age = 20")
       .executeUpdate();
Member findMember = em.find(Member.class, member1.getId());
System.out.println("findMember = " + findMember);

๋ฒŒํฌ ์—ฐ์‚ฐ ์‹œ DB์—๋Š” ์˜ํ–ฅ์„ ์ฃผ์ง€๋งŒ ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ์—๋Š” ๋ฐ˜์˜์ด ๋˜์ง€ ์•Š๋Š”๋‹ค.
๊ทธ๋ž˜์„œ ์ดˆ๊ธฐํ™”๋กœ em.clear() ๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค.






โœ๏ธ OSIV ์ „๋žต

๊ธฐ๋ณธ์ ์œผ๋กœ JPA๊ฐ€ ์–ธ์ œ DB ์ปค๋„ฅ์…˜์„ ๊ฐ€์ง€๊ณ  ์˜ค๊ณ  ์–ธ์ œ DB ์ปค๋„ฅ์…˜์„ DB์— ๋ฐ˜ํ™˜ํ• ๊นŒ??

์ผ๋‹จ ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ๋Š” ๋™์ž‘์„ ํ•˜๋ ค๋ฉด DB ์ปค๋„ฅ์…˜์„ ๋‚ด๋ถ€์ ์œผ๋กœ ์‚ฌ์šฉ์„ ํ•ด์•ผ LAZY ๋กœ๋”ฉ์„ ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ์™€ DB ์ปค๋„ฅ์…˜์„ ๊ต‰์žฅํžˆ ๋ฐ€์ ‘ํ•˜๊ฒŒ ๋งค์นญ์ด ๋˜์–ด ์žˆ๋‹ค.

๊ธฐ๋ณธ์ ์œผ๋กœ DB ํŠธ๋žœ์žญ์…˜์„ ์‹œ์ž‘ํ•  ๋•Œ ์—ฐ์†์„ฑ ์ปจํ…์ŠคํŠธ๊ฐ€ DB ์ปค๋„ฅ์…˜์„ ๊ฐ€์ ธ์˜จ๋‹ค.

๊ทธ๋Ÿฌ๋ฉด ์„œ๋น„์Šค ๊ณ„์ธต์—์„œ ํŠธ๋žœ์žญ์…˜์„ ์‹œ์ž‘ํ•˜๋Š” ์‹œ์ ์— ์ปค๋„ฅ์…˜์„ ๊ฐ€์ ธ์˜ค๊ณ  ์ด์ œ DB์—๋‹ค ๋Œ๋ ค์ค˜์•ผ ํ•˜๋Š”๋ฐ ์ผ๋‹จ spring.jpa.open-in-view ๋กœ default๋กœ ์ผœ์ ธ์žˆ๋‹ค.
์ด ๋•Œ ๋ฐ˜ํ™˜์€ @Transaction ํŠธ๋žœ์žญ์…˜์„ ๋๋‚ด๊ณ  ๋ฐ–์— ๋‚˜๊ฐˆ ๋•Œ๊นŒ์ง€ ๋ฐ˜ํ™˜์„ ํ•˜์ง€ ์•Š๋Š”๋‹ค.
์ด์œ  : LAZY ๋กœ๋”ฉ ์ผ์–ด๋‚  ๋•Œ ํ”„๋ก์‹œ ๊ฐ์ฒด๋ฅผ DB์—์„œ ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์™€์„œ ์ฑ„์šฐ๋“  ํ”„๋ก์‹œ๋ฅผ ์ดˆ๊ธฐํ™”ํ•˜๋“  ํ•ด์•ผ ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ๊ฐ€ DB ์ปค๋„ฅ์…˜์„ ๋ฌผ๊ณ  ์‚ด์•„ ์žˆ์–ด์•ผ ํ•œ๋‹ค.

'๋ฐ–'์˜ ์˜๋ฏธ
๋ฐ–์ด๋ผ๋Š” ๊ฒƒ์€ ํŠธ๋žœ์žญ์…˜์˜ ๋ฒ”์œ„๋ฅผ ๋ฒ—์–ด๋‚œ ์ง€์ ์œผ๋กœ @Transactional ๋ฉ”์„œ๋“œ๊ฐ€ ๋๋‚˜๊ณ  ํŠธ๋žœ์žญ์…˜์ด ์ข…๋ฃŒ๋˜๋Š” ์‹œ์ ์„ ์˜๋ฏธํ•ฉ๋‹ˆ๋‹ค. ์Šคํ”„๋ง์—์„œ๋Š” @Transactional ์–ด๋…ธํ…Œ์ด์…˜์„ ์‚ฌ์šฉํ•˜๋ฉด ํ•ด๋‹น ๋ฉ”์„œ๋“œ๊ฐ€ ์‹คํ–‰๋˜๋Š” ๋™์•ˆ ํŠธ๋žœ์žญ์…˜์ด ์œ ์ง€๋ฉ๋‹ˆ๋‹ค. ํŠธ๋žœ์žญ์…˜์ด ์™„๋ฃŒ๋˜๋ฉด(๋ฉ”์„œ๋“œ ์ข…๋ฃŒ) ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์ปค๋„ฅ์…˜์ด ๋ฐ˜ํ™˜๋ฉ๋‹ˆ๋‹ค.


OSIV๋Š” ์ด ํŠธ๋žœ์žญ์…˜์ด ๋๋‚˜๋„ ์ด ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ๋ฅผ ๋๊นŒ์ง€ ์‚ด๋ ค๋‘”๋‹ค. (API๋ผ๋ฉด ์œ ์ €ํ•œํ…Œ ๋ฐ˜ํ™˜ํ•  ๋•Œ๊นŒ์ง€)

ํ™”๋ฉด์ธ ๊ฒฝ์šฐ๋Š” ๋ทฐ ํ…œํ”Œ๋ฆฟ ๊ฐ€์ง€๊ณ  ๋ Œ๋”๋ง ํ•  ๋•Œ๊นŒ์ง€ ์œ ์ €์—๊ฒŒ response๊ฐ€ ๋‚˜๊ฐˆ ๋•Œ๊นŒ์ง€ DB ์ปค๋„ฅ์…˜์„ ๋ฌผ๊ณ  ์žˆ๋‹ค.
๊ฒฐ๋ก  -> ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ๋ž‘ DB ์ปค๋„ฅ์…˜์ด ๋๊นŒ์ง€ ์‚ด์•„์žˆ๋‹ค.



๐Ÿท๏ธ OSIV ์žฅ๋‹จ์ 

  • ์žฅ์ 
    • View Template์ด๋‚˜ API ์ปจํŠธ๋กค๋Ÿฌ์—์„œ ์ง€์—ฐ ๋กœ๋”ฉ์ด ๊ฐ€๋Šฅํ•œ ๊ฒƒ ์ฒ˜๋Ÿผ ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ์™€ DB ์ปค๋„ฅ์…˜ ์œ ์ง€๊ฐ€ ํฐ ์žฅ์ ์ด๋‹ค.

  • ์น˜๋ช…์ ์ธ ๋‹จ์ 
    • ๋„ˆ๋ฌด ์˜ค๋žซ๋™์•ˆ ์ปค๋„ฅ์…˜์„ ๋ฌผ๊ณ  ์žˆ์Œ.
    • ์‹ค์‹œ๊ฐ„ ํŠธ๋ž˜ํ”ฝ์ด ์ค‘์š”ํ•œ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์—์„œ๋Š” ์ž˜๋ชปํ•˜๋ฉด ์ปค๋„ฅ์…˜์ด ๋ง๋ผ๋ฒ„๋ฆฐ๋‹ค.
      • ์ฆ‰ ์ปจํŠธ๋กค๋Ÿฌ์—์„œ ์™ธ๋ถ€ API๋ฅผ ํ˜ธ์ถœํ•˜๋ฉด ์™ธ๋ถ€ API ๋Œ€๊ธฐ ์‹œ๊ฐ„๋งŒํผ ์ปค๋„ฅ์…˜ ๋ฆฌ์†Œ์Šค๋ฅผ ๋ฐ˜ํ™˜ํ•˜์ง€ ๋ชปํ•˜๊ณ  ์œ ์ง€ํ•˜๊ฒŒ ๋œ๋‹ค.


๊ทธ๋Ÿฌ๋ฉด spring.jpa.open-in-view: false๋กœ ํ•ด์„œ OSIV ์ข…๋ฃŒํ•˜๋ฉด ํŠธ๋žœ์žญ์…˜์„ ์‹œ์ž‘ํ•˜๊ณ  ๋๋‚  ๋•Œ๊นŒ์ง€๋งŒ DB ์ปค๋„ฅ์…˜์„ ์œ ์ง€ํ•œ๋‹ค.
๊ทธ๋ž˜์„œ ์–ด๋–ค ๋กœ์ง, ์™ธ๋ถ€ API ํ˜ธ์ถœํ•ด๋„ DB ์ปค๋„ฅ์…˜ ์•ˆ ๊ฐ€์ง€๊ณ  ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ๋”ฑ ๋ฐ˜ํ™˜ํ•ด์„œ ํŠธ๋ž˜ํ”ฝ์ด ๋งŽ๊ฑฐ๋‚˜ ์‚ฌ์šฉ์ž ์š”์ฒญ์ด ๋งŽ์€ ๊ฒฝ์šฐ์—๋Š” ํ›จ์”ฌ ๋” ์ปค๋„ฅ์…˜์„ ์œ ์—ฐํ•˜๊ฒŒ ์“ธ ์ˆ˜ ์žˆ๋‹ค.



๐Ÿท๏ธ OSIV ๊ป์„ ๋•Œ์˜ ๋‹จ์ 

์ง€์—ฐ ๋กœ๋”ฉ์„ ํ•˜๋ ค๋ฉด ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ๊ฐ€ ์‚ด์•„ ์žˆ์–ด์•ผ ํ•œ๋‹ค.
ํŠธ๋žœ์žญ์…˜ ๋๋‚ฌ๋‹ค๊ณ  ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ๊ฐ€ ์—†์–ด์ ธ๋ฒ„๋ฆฌ๋ฉด ๋ชจ๋“  ์ง€์—ฐ ๋กœ๋”ฉ์„ ํŠธ๋žœ์žญ์…˜ ์•ˆ์—์„œ ์ฒ˜๋ฆฌํ•ด์•ผ ํ•œ๋‹ค.
(์œ„ ๊ทธ๋ฆผ์—์„œ ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ ์ƒ์กด ๋ฒ”์œ„์—์„œ ๋ชจ๋‘ ๋๋‚ด์•ผ ํ•จ.)

๊ฒฐ๋ก  -> ํŠธ๋žœ์žญ์…˜์ด ๋๋‚˜๊ธฐ ์ „์— ์ง€์—ฐ๋กœ๋”ฉ์„ ๊ฐ•์ œ๋กœ ํ˜ธ์ถœํ•ด์•ผ ํ•œ๋‹ค.

  • ์„œ๋น„์Šค ๊ณ„์ธต์ด๋‚˜ ํŒจ์น˜ ์กฐ์ธ์„ ์‚ฌ์šฉํ•˜๊ฑฐ๋‚˜ ํ•ด์„œ ๋‹ค ๋กœ๋”ฉ ๋œ ๊ฒƒ์„ ๊ฐ€์ ธ์™€์•ผ ํ•œ๋‹ค.


๐Ÿท๏ธ open-in-view: false

์ด๊ฒƒ์„ ํ•ด์ฃผ๋ฉด LazyInitializationException ์ด ๋ฐœ์ƒํ•œ๋‹ค.
Member๊ฐ€ proxy์ธ๋ฐ ์ดˆ๊ธฐํ™”๋ฅผ ๋ชปํ•œ๋‹ค.

๊ทธ๋ฆผ์—์„œ ๋ณด๋ฉด Controller์—์„œ ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ๊ฐ€ ์—†๊ธฐ ๋•Œ๋ฌธ์— ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ•œ ๊ฒƒ์ด๋‹ค.
ํŠธ๋žœ์žญ์…˜ ์•ˆ์—์„œ ๋‹ค ๋กœ๋”ฉํ•ด ๋†“๊ฑฐ๋‚˜ fetchJoin์„ ์‚ฌ์šฉํ•ด์„œ ํ•ด๊ฒฐํ•˜๋ฉด ๋œ๋‹ค.
-> ํŠธ๋žœ์žญ์…˜ ์•ˆ์œผ๋กœ ๊ฐ€์ ธ๊ฐ€๋Š” ๊ฒƒ!!



๐Ÿท๏ธ ์‹ค๋ฌด์—์„œ๋Š” OSIV๋ฅผ ๋ˆ ์ƒใ…Œํƒœ๋กœ ๋ณต์žก์„ฑ์„ ๊ด€๋ฆฌํ•˜๋Š” ์ข‹์€ ๋ฐฉ๋ฒ•์ด ์žˆ๋‹ค.

์ปค๋งจ๋“œ์™€ ์ฟผ๋ฆฌ๋ฅผ ๋ถ„๋ฆฌํ•˜๋ฉด ๋œ๋‹ค.
https://en.wikipedia.org/wiki/Command-query_separation

๊ฐœ๋ฐœํ•  ๋•Œ ํ•œ ๋ ˆํฌ์ง€ํ† ๋ฆฌ๋‚˜ ํ•œ ์„œ๋น„์Šค์— ์ฟผ๋ฆฌ์šฉ์ด๋‚˜ ํ•ต์‹ฌ ๋น„์ฆˆ๋‹ˆ์Šค์šฉ์„ ๊ฐ™์ด ๋…น์—ฌ๋†“์œผ๋ฉด ๋ณต์žกํ•œ ์กฐํšŒ์šฉ์ด 20~30๊ฐœ ์ผ ๋•Œ ์œ ์ง€๋ณด์ˆ˜๊ฐ€ ์–ด๋ ค์›Œ์ง„๋‹ค.

  • ๋ผ์ดํ”„ ์‚ฌ์ดํด์ด ๋‹ค๋ฅด๋‹ค
  • ๋Œ€๋ถ€๋ถ„ ํ™”๋ฉด์— ๋งž์ถ”๋Š” API๋‚˜ ํ™”๋ฉด์šฉ ๊ธฐ๋Šฅ๋“ค์€ ์ •๋ง ์ž์ฃผ ๋ฐ”๋€๋‹ค -> ๋ผ์ดํ”„ ์‚ฌ์ดํด์ด ๋น ๋ฆ„
  • ํ•ต์‹ฌ ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง์€ ๊ทธ๋Ÿฐ ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง์ด๋‚˜ ์ •์ฑ…๋“ค์ด ์žˆ๋Š” ์„œ๋น„์Šค ํด๋ž˜์Šค๋Š” ์ž˜ ๋ณ€๊ฒฝ๋˜์ง€ ์•Š๋Š”๋‹ค.
    • ์ด ๋‘˜ ์‚ฌ์ด์˜ ๋ผ์ดํ”„ ์‚ฌ์ดํด์ด ๋‹ค๋ฅด๋‹ค.


Service ์—์„œ ~~Service(ํ•ต์‹ฌ ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง)์™€ ~~QueryService(ํ™”๋ฉด์ด๋‚˜ API์— ๋งž์ถ˜ ์„œ๋น„์Šค๋กœ ์ฃผ๋กœ ์ฝ๊ธฐ ์ „์šฉ ํŠธ๋žœ์žญ์…˜ ์‚ฌ์šฉ)๋กœ ๋‚˜๋ˆ„์–ด์„œ ๊ฐœ๋ฐœํ•˜๋Š” ๊ฒƒ์ด ๋ฐ”๋žŒ์งํ•˜๋‹ค.

๊ฒฐ์ •

๊ณ ๊ฐ ์„œ๋น„์Šค ๊ธฐ๋ฐ˜์˜ ํŠธ๋ž˜ํ”ฝ์ด ๋งŽ์€ ์‹ค์‹œ๊ฐ„ API๋“ค์„ ๋งŽ์ด ์ œ๊ณตํ•ด์•ผ ํ•˜๋Š” API ์„œ๋ฒ„๋Š” off-session-inview ๋„๊ธฐ
์„œ๋น„์Šค API ํŠธ๋ž˜ํ”ฝ์ด ์ •๋ง ๋งŽ๋‹ค๋ฉด ๋„๊ธฐ



ADMIN ์ฒ˜๋Ÿผ ์ปค๋„ฅ์…˜์„ ๋งŽ์ด ์‚ฌ์šฉํ•˜์ง€ ์•Š๋Š” ๊ณณ์—์„œ๋Š” OSIV ์ผœ๊ธฐ.
์ปค๋„ฅ์…˜์„ ๋ช‡ ๊ฐœ ์•ˆ ์“ฐ๊ธฐ ๋•Œ๋ฌธ์—.



๊ธฐ๋ณธ์ ์œผ๋กœ๋Š” ํ‚ค๋Š” ๊ฒƒ์ด ์ข‹๊ธด ํ•œ๋ฐ ์„ฑ๋Šฅ์ด ์ด์Šˆ๊ฐ€ ๋˜๋ฉด ๋„๋Š” ๊ฒƒ์ด ์ข‹๋‹ค.

profile
์ผ์ƒ์˜ ์ธ์—ฐ์— ๊ฐ์‚ฌํ•˜๋ผ. ๊ธฐ์ ์€ ์˜์™ธ๋กœ ๊ฐ€๊นŒ์šด ๊ณณ์— ์žˆ์„์ง€๋„ ๋ชจ๋ฅธ๋‹ค.

0๊ฐœ์˜ ๋Œ“๊ธ€