๋ณธ๋ฌธ ๋ฐ”๋กœ๊ฐ€๊ธฐ
๋ฐฑ์—”๋“œ/spring&springboot

[๋‚ด์ผ๋ฐฐ์›€์บ ํ”„_Spring Boot ์ž…๋ฌธ์ฃผ์ฐจ] JPA CORE

by alswlfl 2026. 6. 25.

JPA๋ž€?

DB๋ฅผ ์ง์ ‘ ๋‹ค๋ฃฐ ๋•Œ์˜ ๋ฌธ์ œ์ 

1. ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์—์„œ ์•„๋ž˜ ํ˜•ํƒœ์˜ ๊ฐ์ฒด ๋ฐ์ดํ„ฐ๋ฅผ DB์— ์ €์žฅํ•ด์„œ ๊ด€๋ฆฌํ•ด์•ผ ํ•œ๋‹ค๋ฉด?

public class Memo {
    private Long id;
    private String username;
    private String contents;
}
  • DB ํ…Œ์ด๋ธ” ์ƒ์„ฑ
  • ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์—์„œ SQL ์ž‘์„ฑ
  • SQL์„ JDBC๋ฅผ ์‚ฌ์šฉํ•ด์„œ ์ง์ ‘ ์‹คํ–‰
  • SQL ๊ฒฐ๊ณผ๋ฅผ ๊ฐ์ฒด๋กœ ์ง์ ‘ ๋งŒ๋“ค๊ธฐ

2. ์œ„์™€ ๊ฐ™์€ ๋ฐฉ๋ฒ•์€ SQL ์˜์กด์ ์ด๋ผ ๋ณ€๊ฒฝ์— ์ทจ์•ฝํ•จ

  • ๋ฉ”๋ชจ ๋ฐ์ดํ„ฐ์— ๋น„๋ฐ€๋ฒˆํ˜ธ๋ฅผ ์ถ”๊ฐ€ํ•ด์•ผ ํ•œ๋‹ค๋ฉด
  • SQL์„ ์ง์ ‘ ์ˆ˜์ •ํ•ด์•ผํ•จ
  • MemoResponseDto ๊ฐ์ฒด์— ๊ฐ’์„ ๋„ฃ์–ด์ฃผ๋Š” ๋ถ€๋ถ„๋„ ๋‹น์—ฐํžˆ ์ถ”๊ฐ€ํ•ด์ค˜์•ผํ•จ

์ฆ‰, ORM์ด ์—†๋Š” ํ™˜๊ฒฝ์—์„œ๋Š” ๊ฐœ๋ฐœ์ž๊ฐ€ ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง ๊ฐœ๋ฐœ๋ณด๋‹ค๋Š” SQL ์ž‘์„ฑ ๋ฐ ์ˆ˜์ •์— ๋” ๋งŽ์€ ๋…ธ๋ ฅ์„ ๋“ค์˜€์–ด์•ผ ํ–ˆ์Œ

ORM(Object-Relational Mapping)

  • Object: "๊ฐ์ฒด"์ง€ํ–ฅ ์–ธ์–ด(์ž๋ฐ”, ํŒŒ์ด์ฌ)
  • Relational: "๊ด€๊ณ„ํ˜•" ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค(H2, MySQL)

์ฆ‰, ORM์€ ๊ฐ์ฒด์™€ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค๋ฅผ ๋งตํ•‘ํ•ด์ฃผ๋Š” ๋„๊ตฌ

  • ๋ฐ˜๋ณต์ ์ด๊ณ  ๋ฒˆ๊ฑฐ๋กœ์šด ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ๋‹จ์˜ SQL ์ž‘์—…์„ ์ค„์—ฌ์ฃผ๊ธฐ ์œ„ํ•ด ๋“ฑ์žฅ

ORM

JPA(Java Persistence API)

Java ORM ๊ธฐ์ˆ ์˜ ๋Œ€ํ‘œ์ ์ธ ํ‘œ์ค€ ๋ช…์„ธ

JPA

Hibernate: JPA๋ฅผ ์‹ค์ œ๋กœ ๊ตฌํ˜„ํ•œ ํ”„๋ ˆ์ž„์›Œํฌ


Entity ์ดํ•ดํ•˜๊ธฐ

Entity๋Š” JPA์—์„œ ๊ด€๋ฆฌ๋˜๊ณ  ์žˆ๋Š” Class, ์ฆ‰ ๊ฐ์ฒด๋ฅผ ์˜๋ฏธํ•จ.

Entity Class๋Š” ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์˜ table๊ณผ ๋งตํ•‘์ด ๋˜์–ด์„œ JPA์— ์˜ํ•ด์„œ ๊ด€๋ฆฌ๋˜๊ณ  ์žˆ์Œ

Entity

Java ํ™˜๊ฒฝ์—์„œ JPA ์‚ฌ์šฉํ•˜๊ธฐ

1. persistence.xml ํŒŒ์ผ๊ณผ build.gradle ํŒŒ์ผ ์ˆ˜์ •

persistence.xml

2. Entity ์ƒ์„ฑ

package com.sparta.entity;

import jakarta.persistence.*;

@Entity // JPA๊ฐ€ ๊ด€๋ฆฌํ•  ์ˆ˜ ์žˆ๋Š” Entity ํด๋ž˜์Šค ์ง€์ •
@Table(name = "memo") // ๋งคํ•‘ํ•  ํ…Œ์ด๋ธ”์˜ ์ด๋ฆ„์„ ์ง€์ •
public class Memo {
    @Id // table์˜ ๊ธฐ๋ณธ ํ‚ค ์ง€์ •
    @GeneratedValue(strategy = GenerationType.IDENTITY) // AUTO_INCREMENT ์˜ต
    private Long id;

    // nullable: null ํ—ˆ์šฉ ์—ฌ๋ถ€
    // unique: ์ค‘๋ณต ํ—ˆ์šฉ ์—ฌ๋ถ€ (false ์ผ๋•Œ ์ค‘๋ณต ํ—ˆ์šฉ)
    @Column(name = "username", nullable = false, unique = true)
    private String username;

    // length: ์ปฌ๋Ÿผ ๊ธธ์ด ์ง€์ •
    @Column(name = "contents", nullable = false, length = 500)
    private String contents;
}
  • @Entity: JPA๊ฐ€ ๊ด€๋ฆฌํ•  ์ˆ˜ ์žˆ๋Š” Entity ํด๋ž˜์Šค๋กœ ์ง€์ •
    • @Entity(name="Memo"): Entity ํด๋ž˜์Šค ์ด๋ฆ„ ์ง€์ • ๊ฐ€๋Šฅ(default: ํด๋ž˜์Šค๋ช…)
    • JPA๊ฐ€ Entity ํด๋ž˜์Šค๋ฅผ ์ธ์Šคํ„ด์Šคํ™”ํ•  ๋•Œ ๊ธฐ๋ณธ ์ƒ์„ฑ์ž๋ฅผ ์‚ฌ์šฉํ•˜๊ธฐ ๋•Œ๋ฌธ์— ํ˜„์žฌ Entity ํด๋ž˜์Šค์—์„œ ๊ธฐ๋ณธ ์ƒ์„ฑ์ž๊ฐ€ ๋˜๊ณ  ์žˆ๋Š”์ง€ ํ™•์ธํ•ด์•ผ ํ•จ
  • @Table: ๋งคํ•‘ํ•  ํ…Œ์ด๋ธ” ์ง€์ •
    • @Table(name="memo"): ๋งคํ•‘ํ•  ํ…Œ์ด๋ธ”์˜ ์ด๋ฆ„ ์ง€์ • ๊ฐ€๋Šฅ(default: Entity ๋ช…)
  • @Column
    • @Column(name="username"): ํ•„๋“œ์™€ ๋งคํ•‘ํ•  ํ…Œ์ด๋ธ”์˜ ์ปฌ๋Ÿผ ์ง€์ • ๊ฐ€๋Šฅ(default: ๊ฐ์ฒด์˜ ํ•„๋“œ๋ช…)
    • @Column(nullable=false): ๋ฐ์ดํ„ฐ์˜ null ๊ฐ’ ํ—ˆ์šฉ ์—ฌ๋ถ€ ์ง€์ •(default: true)
    • @Column(unique=true): ๋ฐ์ดํ„ฐ์˜ ์ค‘๋ณต ๊ฐ’ ํ—ˆ์šฉ ์—ฌ๋ถ€ ์ง€์ •(default: false → null ๊ฐ’ ํ—ˆ์šฉ O)
    • @Column(length=500): ๋ฐ์ดํ„ฐ ๊ฐ’(๋ฌธ์ž)์˜ ๊ธธ์ด์— ์ œ์•ฝ์กฐ๊ฑด ๊ฑธ ์ˆ˜ ์žˆ์Œ(default: 255)
  • @Id: ํ…Œ์ด๋ธ”์˜ ๊ธฐ๋ณธ ํ‚ค๋ฅผ ์ง€์ •
    • ๊ธฐ๋ณธ ํ‚ค๋Š” ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ์—์„œ Entity๋ฅผ ๊ตฌ๋ถ„ํ•˜๊ณ  ๊ด€๋ฆฌํ•  ๋•Œ ์‚ฌ์šฉ๋˜๋Š” ์‹๋ณ„์ž ์—ญํ•  ์ˆ˜ํ–‰ํ•จ. ๋”ฐ๋ผ์„œ ๊ธฐ๋ณธ ํ‚ค ์ฆ‰, ์‹๋ณ„์ž๋ฅผ ๋„ฃ์–ด์ฃผ์ง€ ์•Š๊ณ  ์ €์žฅํ•˜๋ฉด ์˜ค๋ฅ˜ ๋ฐœ์ƒํ•จ
    • @Id ์˜ต์…˜๋งŒ ์„ค์ •ํ•˜๋ฉด ๊ธฐ๋ณธ ํ‚ค ๊ฐ’์„ ๊ฐœ๋ฐœ์ž๊ฐ€ ์ง์ ‘ ํ™•์ธํ•˜๊ณ  ๋„ฃ์–ด์ค˜์•ผ ํ•˜๋Š” ๋ถˆํŽธํ•จ ๋ฐœ์ƒํ•จ
    • @GeneratedValue ์˜ต์…˜์„ ์ถ”๊ฐ€ํ•˜๋ฉด ๊ธฐ๋ณธ ํ‚จ ์ƒ์„ฑ์„ DB์— ์œ„์ž„ ๊ฐ€๋Šฅ
    • @GeneratedValue(strategy = GenerationType.IDENTITY): ์ž๋™์œผ๋กœ ์ˆœ์„œ์— ๋งž๊ฒŒ ๊ธฐ๋ณธ ํ‚ค ์ถ”๊ฐ€๋จ

3. Entity๋กœ ํ…Œ์ด๋ธ” ๋งŒ๋“ค์–ด๋ƒ„

๊ฒฐ๊ณผ

 

๐Ÿ—ฃ๏ธ JPA ๊ธฐ๋ณธ ํ‚ค ์ƒ์„ฑ @GeneratedValue strategy ์˜ต์…˜

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;

 

strategy ์˜ต์…˜์€ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์—์„œ ์ž๋™์œผ๋กœ ID๋ฅผ ์ƒ์„ฑํ•˜๋Š” ๋ฐฉ๋ฒ• ์ง€์ •

 

1. AUTO

  • ์˜ต์…˜์„ ์„ ํƒํ•˜์ง€ ์•Š๋Š” ๊ฒฝ์šฐ ๋””ํดํŠธ ๊ฐ’
  • JPA๊ฐ€ ์‚ฌ์šฉ ์ค‘์ธ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์— ๋”ฐ๋ผ ์ž๋™์œผ๋กœ ๊ฐ€์žฅ ์ ์ ˆํ•œ ๋ฐฉ๋ฒ• ์„ ํƒ
  • ex) MySQL์—๋Š” IDENTITY, Oracle์€ SEQUENCE ์„ ํƒ

2. IDENTITY

  • ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค๊ฐ€ ์ง์ ‘ ID๋ฅผ ์ƒ์„ฑํ•ด ๋ฒˆํ˜ธ๋ฅผ ๋งค๊ธฐ๋Š” ๊ฒƒ
  • ID ์–ด๋…ธํ…Œ์ด์…˜์œผ๋กœ ๊ธฐ๋ณธํ‚ค๋ฅผ ๋งŒ๋“ค ๋•Œ ๊ฐ€์žฅ ๋งŽ์ด ์‚ฌ์šฉํ•œ ์˜ต์…˜
  • ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์—์„œ ์ƒˆ๋กœ ์ €์žฅ๋˜๋Š” ๋ฐ์ดํ„ฐ๋งˆ๋‹ค ์ž๋™์œผ๋กœ ์ˆซ์ž๊ฐ€ 1์”ฉ ์ฆ๊ฐ€ํ•˜๋Š” ๋ฐฉ์‹์œผ๋กœ ID๋ฅผ ์ƒ์„ฑ
  • ์ฃผ๋กœ MySQL, SQL Server ๋“ฑ์˜ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์—์„œ ์‚ฌ์šฉ๋จ

3. SEQUENCE

  • ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์˜ '์‹œํ€€์Šค'๋ผ๋Š” ๊ฐ์ฒด๋ฅผ ์‚ฌ์šฉํ•ด์„œ ๊ธฐ๋ณธ ํ‚ค ๊ฐ’์„ ์ƒ์„ฑํ•จ, ์‹œํ€€์Šค ๊ฐ์ฒด๋Š” ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์—์„œ ๋ฏธ๋ฆฌ ์ •์˜
  • ID๋ฅผ ๋ฏธ๋ฆฌ ๋งŒ๋“ค์–ด ๊ด€๋ฆฌ ๊ฐ€๋Šฅ
  • ์—ฌ๋Ÿฌ ์—”ํ‹ฐํ‹ฐ์—์„œ ๋™์ผํ•œ ์‹œํ€€์Šค๋ฅผ ๊ณต์œ ํ•  ์ˆ˜ ์žˆ์Œ
  • ์„ฑ๋Šฅ ์šฐ์ˆ˜
  • ์ฃผ๋กœ Oracle, PostgreSQL ๊ฐ™์€ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์—์„œ ์‚ฌ์šฉ๋จ

4. TABLE

  • ๋ณ„๋„์˜ ํ…Œ์ด๋ธ”์„ ๋งŒ๋“ค์–ด ID ๊ด€๋ฆฌ
  • ๋ชจ๋“  ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์—์„œ ์‚ฌ์šฉ, ๋™์ผํ•˜๊ฒŒ ๋™์ž‘
  • ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ๋…๋ฆฝ์ 
  • ๋‹ค์†Œ ๋ณต์žกํ•˜๊ณ  ์„ฑ๋Šฅ์ด ๋–จ์–ด์งˆ ์ˆ˜ ์žˆ์Œ

 

๐Ÿ—ฃ๏ธ hibernate.hbm2ddl.auto ์†์„ฑ

๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์Šคํ‚ค๋งˆ ์ž๋™ ์ƒ์„ฑ
- DDL์„ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์‹คํ–‰ ์‹œ์ ์— ์ž๋™ ์ƒ์„ฑํ•จ
- ํ…Œ์ด๋ธ” ์ค‘์‹ฌ์—์„œ ๊ฐ์ฒด ์ค‘์‹ฌ์œผ๋กœ ์ด๋™
- ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ๋ฐฉ์–ธ์„ ํ™œ์šฉํ•ด ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์— ๋งž๋Š” ์ ์ ˆํ•œ DDL ์ƒ์„ฑ
- ์ƒ์„ฑ๋œ DLL์€ ๊ฐœ๋ฐœ ๋‹จ๊ณ„์—์„œ๋งŒ ์‚ฌ์šฉ๋จ(์šด์˜ ์„œ๋ฒ„์—๋Š” ์ ์ ˆํžˆ ๋‹ค๋“ฌ์€ ํ›„ ์‚ฌ์šฉ)

 

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

2. create-drop: CREATE์™€ ๊ฐ™์ง€๋งŒ ์ข…๋ฃŒ ์‹œ์ ์—(DROP)

3. update: ๋ณ€๊ฒฝ ๋ถ„๋งŒ ๋ฐ˜์˜(์ถ”๊ฐ€๋งŒ ๋˜๊ณ  ์ง€์›Œ์ง€๋Š” ๊ฒƒ์€ ์•ˆ๋จ)

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

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

 

โ€ผ๏ธ ์ฃผ์˜ํ•  ์ 

- ์šด์˜์žฅ๋น„์—๋Š” ์ ˆ๋Œ€ create, create-drop, update ์‚ฌ์šฉํ•˜๋ฉด ์•ˆ๋จ!(๋ฐ์ดํ„ฐ๊ฐ€ ์—†์–ด์งˆ ์œ„ํ—˜ ์กด์žฌ)

- ๊ฐœ๋ฐœ ์ดˆ๊ธฐ ๋‹จ๊ณ„๋Š” create ๋˜๋Š” update

- ํ…Œ์ŠคํŠธ ์„œ๋ฒ„๋Š” update ๋˜๋Š” validate

- ์šด์˜ ์„œ๋ฒ„๋Š” validate ๋˜๋Š” none


์˜์†์„ฑ ์ปจํ…์ŠคํŠธ(Persistence)

Persistence๋Š” ์˜์†์„ฑ, ์ง€์†์„ฑ์ด๋ผ๋Š” ๋œป์œผ๋กœ,

๊ฐ์ฒด์˜ ๊ด€์ ์œผ๋กœ ํ•ด์„ํ•˜๋ฉด, '๊ฐ์ฒด๊ฐ€ ์ƒ๋ช…(๊ฐ์ฒด๊ฐ€ ์œ ์ง€๋˜๋Š” ์‹œ๊ฐ„)์ด๋‚˜ ๊ณต๊ฐ„(๊ฐ์ฒด์˜ ์œ„์น˜)์„ ์ž์œ ๋กญ๊ฒŒ ์œ ์ง€ํ•˜๊ณ  ์ด๋™ํ•  ์ˆ˜ ์žˆ๋Š” ๊ฐ์ฒด์˜ ์„ฑ์งˆ์„ ์˜๋ฏธ

์ฆ‰, Entity ๊ฐ์ฒด๋ฅผ ํšจ์œจ์ ์œผ๋กœ ์‰ฝ๊ฒŒ ๊ด€๋ฆฌํ•˜๊ธฐ ์œ„ํ•ด ๋งŒ๋“ค์–ด์ง„ ๊ณต๊ฐ„์ž„

์˜์†์„ฑ ์ปจํ…์ŠคํŠธ

  • ๊ฐœ๋ฐœ์ž๋“ค์€ SQL์„ ์ž‘์„ฑํ•˜์ง€ ์•Š์•„๋„ JPA๋ฅผ ์‚ฌ์šฉํ•ด DB์— ๋ฐ์ดํ„ฐ๋ฅผ ์ €์žฅํ•˜๊ฑฐ๋‚˜ ์กฐํšŒํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ, ์ˆ˜์ •๊ณผ ์‚ญ์ œ๋„ ๊ฐ€๋Šฅํ•จ
  • ์ด๋Ÿฌํ•œ ์ผ๋ จ์˜ ๊ณผ์ •์„ ํšจ์œจ์ ์„ ์ฒ˜๋ฆฌํ•˜๊ธฐ ์œ„ํ•ด JPA๋Š” ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ์— Entity ๊ฐ์ฒด๋“ค์„ ์ €์žฅํ•˜์—ฌ ๊ด€๋ฆฌํ•˜๋ฉด์„œ DB์™€ ์†Œํ†ตํ•จ

EntityManager

์˜์†์„ฑ ์ปจํ…์ŠคํŠธ์— ์ ‘๊ทผํ•ด Entity ๊ฐ์ฒด๋ฅผ ์กฐ์ž‘ํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” EntityManager๊ฐ€ ํ•„์š”ํ•จ

EntityManager๋Š” Entity๋ฅผ ๊ด€๋ฆฌํ•˜๋Š” ๊ด€๋ฆฌ์ž

Entity Manager

  • ๊ฐœ๋ฐœ์ž๋“ค์€ EntityManager๋ฅผ ์‚ฌ์šฉํ•ด Entity๋ฅผ ์ €์žฅํ•˜๊ณ  ์กฐํšŒํ•˜๊ณ  ์ˆ˜์ •ํ•˜๊ณ  ์‚ญ์ œํ•  ์ˆ˜ ์žˆ์Œ
  • EntityManager๋Š” EntityManagerFactory๋ฅผ ํ†ตํ•ด ์ƒ์„ฑํ•ด ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Œ

EntityManagerFactory

EntityManagerFactory

EntityManagerFactory๋Š” ์ผ๋ฐ˜์ ์œผ๋กœ DB ํ•˜๋‚˜์— ํ•˜๋‚˜๋งŒ ์ƒ์„ฑ๋˜์–ด ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์ด ๋™์ž‘ํ•˜๋Š” ๋™์•ˆ ์‚ฌ์šฉ๋จ

  • EntityManagerFactory๋ฅผ ๋งŒ๋“ค๊ธฐ ์œ„ํ•ด์„œ๋Š” DB์— ๋Œ€ํ•œ ์ •๋ณด๋ฅผ ์ „๋‹ฌํ•ด์•ผํ•จ
    ์ •๋ณด๋ฅผ ์ „๋‹ฌํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” /resources/META-INF/ ์œ„์น˜์— persistence.xml ํŒŒ์ผ์„ ๋งŒ๋“ค์–ด ์ •๋ณด๋ฅผ ๋„ฃ์–ด๋‘๋ฉด๋จ
<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.2"
             xmlns="http://xmlns.jcp.org/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence http://xmlns.jcp.org/xml/ns/persistence/persistence_2_2.xsd">
    <persistence-unit name="memo">
        <class>com.sparta.entity.Memo</class>
        <properties>
            <property name="jakarta.persistence.jdbc.driver" value="com.mysql.cj.jdbc.Driver"/>
            <property name="jakarta.persistence.jdbc.user" value="root"/>
            <property name="jakarta.persistence.jdbc.password" value="{๋น„๋ฐ€๋ฒˆํ˜ธ}"/>
            <property name="jakarta.persistence.jdbc.url" value="jdbc:mysql://localhost:3306/memo"/>

            <property name="hibernate.hbm2ddl.auto" value="create" />

            <property name="hibernate.show_sql" value="true"/>
            <property name="hibernate.format_sql" value="true"/>
            <property name="hibernate.use_sql_comments" value="true"/>
        </properties>
    </persistence-unit>
</persistence>
EntityManagerFactory emf = Persistence.createEntityManagerFactory("memo"); // persistence-unit ์ด๋ฆ„
EntityManager em = emf.createEntityManager(); // EntityManager ์ƒ์„ฑ

JPA ํŠธ๋žœ์žญ์…˜

ํŠธ๋žœ์žญ์…˜

DB ๋ฐ์ดํ„ฐ๋“ค์˜ ๋ฌด๊ฒฐ์„ฑ๊ณผ ์ •ํ•ฉ์„ฑ์„ ์œ ์ง€ํ•˜๊ธฐ ์œ„ํ•œ ํ•˜๋‚˜์˜ ๋…ผ๋ฆฌ์  ๊ฐœ๋…์œผ๋กœ, ์ฆ‰ DB์˜ ๋ฐ์ดํ„ฐ๋“ค์„ ์•ˆ์ „ํ•˜๊ฒŒ ๊ด€๋ฆฌํ•˜๊ธฐ ์œ„ํ•ด์„œ ์ƒ๊ฒจ๋‚œ ๊ฐœ๋…

  • ์—ฌ๋Ÿฌ ๊ฐœ์˜ SQL์ด ํ•˜๋‚˜์˜ ํŠธ๋žœ์žญ์…˜์— ํฌํ•จ๋  ์ˆ˜ ์žˆ์Œ
  • ๋ชจ๋“  SQL์ด ์„ฑ๊ณต์ ์œผ๋กœ ์ˆ˜ํ–‰์ด ๋˜๋ฉด DB์— ์˜๊ตฌ์ ์œผ๋กœ ๋ณ€๊ฒฝ์„ ๋ฐ˜์˜ํ•˜์ง€๋งŒ SQL ์ค‘ ๋‹จ ํ•˜๋‚˜๋ผ๋„ ์‹คํŒจํ•œ๋‹ค๋ฉด ๋ชจ๋“  ๋ณ€๊ฒฝ์„ ๋˜๋Œ๋ฆผ

ํŠธ๋žœ์žญ์…˜

START TRANSACTION; # ํŠธ๋žœ์žญ์…˜์„ ์‹œ์ž‘ํ•ฉ๋‹ˆ๋‹ค.

INSERT INTO memo (id, username, contents) VALUES (1, 'Robbie', 'Robbie Memo');
INSERT INTO memo (id, username, contents) VALUES (2, 'Robbert', 'Robbert Memo');
SELECT * FROM memo;

COMMIT; # ํŠธ๋žœ์žญ์…˜์„ ์ปค๋ฐ‹ํ•ฉ๋‹ˆ๋‹ค.

SELECT * FROM memo;
  • COMMIT์„ ํ•ด์•ผ์ง€ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์— ๋ฐ˜์˜๋จ

๏นกJPA๋Š” DB์˜ ํŠธ๋žœ์žญ์…˜ ๊ฐœ๋…์„ ์‚ฌ์šฉํ•ด ํšจ์œจ์ ์œผ๋กœ Entity๋ฅผ ๊ด€๋ฆฌํ•˜๊ณ  ์žˆ์Œ

 

JPA ํŠธ๋žœ์žญ์…˜

DB์—์„œ ํ•˜๋‚˜์˜ ํŠธ๋žœ์žญ์…˜์— ์—ฌ๋Ÿฌ ๊ฐœ์˜ SQL์„ ํฌํ•จํ•˜๊ณ  ์žˆ๋‹ค๊ฐ€ ๋งˆ์ง€๋ง‰์— ์˜๊ตฌ์ ์œผ๋กœ ๋ณ€๊ฒฝ์„ ๋ฐ˜์˜ํ•˜๋Š” ๊ฒƒ์ฒ˜๋Ÿผ,

JPA์—์„œ๋„ ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ๋กœ ๊ด€๋ฆฌํ•˜๊ณ  ์žˆ๋Š” ๋ณ€๊ฒฝ์ด ๋ฐœ์ƒํ•œ ๊ฐ์ฒด๋“ค์˜ ์ •๋ณด๋ฅผ ์“ฐ๊ธฐ ์ง€์—ฐ ์ €์žฅ์†Œ์— ์ „๋ถ€ ๊ฐ€์ง€๊ณ  ์žˆ๋‹ค๊ฐ€ ๋งˆ์ง€๋ง‰์— SQL์„ ํ•œ๋ฒˆ์— DB์— ์š”์ฒญํ•ด ๋ณ€๊ฒฝ์„ ๋ฐ˜์˜ํ•จ

JPA ํŠธ๋žœ์žญ์…˜

EntityํŠธ๋žœ์žญ์…˜ ์„ฑ๊ณต ํ…Œ์ŠคํŠธ

import com.sparta.entity.Memo;
import jakarta.persistence.EntityManager;
import jakarta.persistence.EntityManagerFactory;
import jakarta.persistence.EntityTransaction;
import jakarta.persistence.Persistence;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;

public class EntityTest {

    EntityManagerFactory emf;
    EntityManager em;

    @BeforeEach
    void setUp() {
        emf = Persistence.createEntityManagerFactory("memo");
        em = emf.createEntityManager();
    }

    @Test
    @DisplayName("EntityTransaction ์„ฑ๊ณต ํ…Œ์ŠคํŠธ")
    void test1() {
        EntityTransaction et = em.getTransaction(); // EntityManager ์—์„œ EntityTransaction ์„ ๊ฐ€์ ธ์˜ต๋‹ˆ๋‹ค.

        et.begin(); // ํŠธ๋žœ์žญ์…˜์„ ์‹œ์ž‘ํ•ฉ๋‹ˆ๋‹ค.

        try { // DB ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•ฉ๋‹ˆ๋‹ค.

            Memo memo = new Memo(); // ์ €์žฅํ•  Entity ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค.
            memo.setId(1L); // ์‹๋ณ„์ž ๊ฐ’์„ ๋„ฃ์–ด์ค๋‹ˆ๋‹ค.
            memo.setUsername("Robbie");
            memo.setContents("์˜์†์„ฑ ์ปจํ…์ŠคํŠธ์™€ ํŠธ๋žœ์žญ์…˜ ์ดํ•ดํ•˜๊ธฐ");

            em.persist(memo); // EntityManager ์‚ฌ์šฉํ•˜์—ฌ memo ๊ฐ์ฒด๋ฅผ ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ์— ์ €์žฅํ•ฉ๋‹ˆ๋‹ค.

            et.commit(); // ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•˜์ง€ ์•Š๊ณ  ์ •์ƒ์ ์œผ๋กœ ์ˆ˜ํ–‰๋˜์—ˆ๋‹ค๋ฉด commit ์„ ํ˜ธ์ถœํ•ฉ๋‹ˆ๋‹ค.
            // commit ์ด ํ˜ธ์ถœ๋˜๋ฉด์„œ DB ์— ์ˆ˜ํ–‰ํ•œ DB ์ž‘์—…๋“ค์ด ๋ฐ˜์˜๋ฉ๋‹ˆ๋‹ค.
        } catch (Exception ex) {
            ex.printStackTrace();
            et.rollback(); // DB ์ž‘์—… ์ค‘ ์˜ค๋ฅ˜ ๋ฐœ์ƒ ์‹œ rollback ์„ ํ˜ธ์ถœํ•ฉ๋‹ˆ๋‹ค.
        } finally {
            em.close(); // ์‚ฌ์šฉํ•œ EntityManager ๋ฅผ ์ข…๋ฃŒํ•ฉ๋‹ˆ๋‹ค.
        }

        emf.close(); // ์‚ฌ์šฉํ•œ EntityManagerFactory ๋ฅผ ์ข…๋ฃŒํ•ฉ๋‹ˆ๋‹ค.
    }

}

PK

 

EntityํŠธ๋žœ์žญ์…˜ ์‹คํŒจ ํ…Œ์ŠคํŠธ

@Test
@DisplayName("EntityTransaction ์‹คํŒจ ํ…Œ์ŠคํŠธ")
void test2() {
    EntityTransaction et = em.getTransaction(); // EntityManager ์—์„œ EntityTransaction ์„ ๊ฐ€์ ธ์˜ต๋‹ˆ๋‹ค.

    et.begin(); // ํŠธ๋žœ์žญ์…˜์„ ์‹œ์ž‘ํ•ฉ๋‹ˆ๋‹ค.

    try { // DB ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•ฉ๋‹ˆ๋‹ค.

        Memo memo = new Memo(); // ์ €์žฅํ•  Entity ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค.
        memo.setUsername("Robbert");
        memo.setContents("์‹คํŒจ ์ผ€์ด์Šค");

        em.persist(memo); // EntityManager ์‚ฌ์šฉํ•˜์—ฌ memo ๊ฐ์ฒด๋ฅผ ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ์— ์ €์žฅํ•ฉ๋‹ˆ๋‹ค.

        et.commit(); // ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•˜์ง€ ์•Š๊ณ  ์ •์ƒ์ ์œผ๋กœ ์ˆ˜ํ–‰๋˜์—ˆ๋‹ค๋ฉด commit ์„ ํ˜ธ์ถœํ•ฉ๋‹ˆ๋‹ค.
        // commit ์ด ํ˜ธ์ถœ๋˜๋ฉด์„œ DB ์— ์ˆ˜ํ–‰ํ•œ DB ์ž‘์—…๋“ค์ด ๋ฐ˜์˜๋ฉ๋‹ˆ๋‹ค.
    } catch (Exception ex) {
        System.out.println("์‹๋ณ„์ž ๊ฐ’์„ ๋„ฃ์–ด์ฃผ์ง€ ์•Š์•„ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ–ˆ์Šต๋‹ˆ๋‹ค.");
        ex.printStackTrace();
        et.rollback(); // DB ์ž‘์—… ์ค‘ ์˜ค๋ฅ˜ ๋ฐœ์ƒ ์‹œ rollback ์„ ํ˜ธ์ถœํ•ฉ๋‹ˆ๋‹ค.
    } finally {
        em.close(); // ์‚ฌ์šฉํ•œ EntityManager ๋ฅผ ์ข…๋ฃŒํ•ฉ๋‹ˆ๋‹ค.
    }

    emf.close(); // ์‚ฌ์šฉํ•œ EntityManagerFactory ๋ฅผ ์ข…๋ฃŒํ•ฉ๋‹ˆ๋‹ค.
}

๊ฒฐ๊ณผ


์˜์†์„ฑ ์ปจํ…์ŠคํŠธ์˜ ๊ธฐ๋Šฅ

๊ธฐ๋Šฅ 1) 1์ฐจ ์บ์‹œ

์˜์†์„ฑ ์ปจํ…์ŠคํŠธ๋Š” ๋‚ด๋ถ€์ ์œผ๋กœ ์บ์‹œ ์ €์žฅ์†Œ๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ์Œ

์˜์†์„ฑ ์ปจํ…์ŠคํŠธ์˜ 1์ฐจ ์บ์‹œ

  • ์ €์žฅํ•˜๋Š” Entity ๊ฐ์ฒด๋“ค์ด 1์ฐจ ์บ์‹œ ์ฆ‰, ์บ์‹œ ์ €์žฅ์†Œ์— ์ €์žฅ๋จ
  • ์บ์‹œ ์ €์žฅ์†Œ๋Š” Map ์ž๋ฃŒ๊ตฌ์กฐ ํ˜•ํƒœ๋กœ ๋˜์–ด์žˆ์Œ
    • key์—๋Š” @Id๋กœ ๋งคํ•‘ํ•œ ๊ธฐ๋ณธ ํ‚ค์ธ ์‹๋ณ„์ž ๊ฐ’์„ ์ €์žฅํ•จ
    • value์—๋Š” ํ•ด๋‹น Entity ํด๋ž˜์Šค์˜ ๊ฐ์ฒด๋ฅผ ์ €์žฅํ•จ
    • ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ๋Š” ์บ์‹œ ์ €์žฅ์†Œ Key์— ์ €์žฅํ•œ ์‹๋ณ„์ž๊ฐ’์„ ์‚ฌ์šฉํ•ด Entity ๊ฐ์ฒด๋ฅผ ๊ตฌ๋ถ„ํ•˜๊ณ  ๊ด€๋ฆฌํ•จ

์˜์†์„ฑ ์ปจํ…์ŠคํŠธ์˜ ์บ์‹œ ์ €์žฅ์†Œ ํ™œ์šฉ

Entity ์ €์žฅ

Entity ์ €์žฅ

em.persist(memo); ๋ฉ”์„œ๋“œ๊ฐ€ ํ˜ธ์ถœ๋˜๋ฉด memo Entity ๊ฐ์ฒด๋ฅผ ์บ์‹œ ์ €์žฅ์†Œ์— ์ €์žฅํ•จ

@Test
@DisplayName("1์ฐจ ์บ์‹œ : Entity ์ €์žฅ")
void test1() {
    EntityTransaction et = em.getTransaction();

    et.begin();

    try {

        Memo memo = new Memo();
        memo.setId(1L);
        memo.setUsername("Robbie");
        memo.setContents("1์ฐจ ์บ์‹œ Entity ์ €์žฅ");

        em.persist(memo);

        et.commit();

    } catch (Exception ex) {
        ex.printStackTrace();
        et.rollback();
    } finally {
        em.close();
    }

    emf.close();
}

  • em > persistenceContext > entitiesBykey๋ฅผ ํ™•์ธํ•˜๋ฉด key-value ํ˜•ํƒœ๋กœ ์ •๋ณด๊ฐ€ ์ €์žฅ๋˜์–ด ์žˆ๋Š” ๊ฑธ ๋ณผ ์ˆ˜ ์žˆ์Œ

Entity ์กฐํšŒ

1. ์บ์‹œ ์ €์žฅ์†Œ์— ์กฐํšŒํ•˜๋Š” Id๊ฐ€ ์กด์žฌํ•˜์ง€ ์•Š์€ ๊ฒฝ์šฐ

  • em.find(Memo.class, 1); ํ˜ธ์ถœ ์‹œ ์บ์‹œ ์ €์žฅ์†Œ๋ฅผ ํ™•์ธํ•œ ํ›„ ํ•ด๋‹น ๊ฐ’์ด ์—†์œผ๋ฉด, DB์— SELECT ์กฐํšŒ ํ›„ ํ•ด๋‹น ๊ฐ’์„ ์บ์‹œ ์ €์žฅ์†Œ์— ์ €์žฅํ•˜๊ณ  ๋ฐ˜ํ™˜ํ•จ
@Test
@DisplayName("Entity ์กฐํšŒ : ์บ์‹œ ์ €์žฅ์†Œ์— ํ•ด๋‹นํ•˜๋Š” Id๊ฐ€ ์กด์žฌํ•˜์ง€ ์•Š์€ ๊ฒฝ์šฐ")
void test2() {
    try {

        Memo memo = em.find(Memo.class, 1);
        System.out.println("memo.getId() = " + memo.getId());
        System.out.println("memo.getUsername() = " + memo.getUsername());
        System.out.println("memo.getContents() = " + memo.getContents());


    } catch (Exception ex) {
        ex.printStackTrace();
    } finally {
        em.close();
    }

    emf.close();
}

์กฐํšŒ ์‹œ ์—†์œผ๋ฉด DB์—์„œ ์ฐพ์•„์˜จ ํ›„ ๋ฐ˜ํ™˜

 

2. ์บ์‹œ ์ €์žฅ์†Œ์— ์กฐํšŒํ•˜๋Š” Id๊ฐ€ ์กด์žฌํ•˜๋Š” ๊ฒฝ์šฐ

์บ์‹œ ์ €์žฅ์†Œ์— ์กด์žฌํ•˜๋Š” ๊ฒฝ์šฐ

  • em.find(Memo.class, 1); ํ˜ธ์ถœ ์‹œ ์บ์‹œ ์ €์žฅ์†Œ์— ์‹๋ณ„์ž ๊ฐ’์ด 1์ด๋ฉด์„œ Memo Entity ํƒ€์ž…์ธ ๊ฐ’์ด ์žˆ๋Š”์ง€ ์กฐํšŒ ํ›„, ๊ฐ’์ด ์žˆ๋‹ค๋ฉด ํ•ด๋‹น Entity ๊ฐ์ฒด๋ฅผ ๋ฐ˜ํ™˜ํ•จ
@Test
@DisplayName("Entity ์กฐํšŒ : ์บ์‹œ ์ €์žฅ์†Œ์— ํ•ด๋‹นํ•˜๋Š” Id๊ฐ€ ์กด์žฌํ•˜๋Š” ๊ฒฝ์šฐ")
void test3() {
    try {

        Memo memo1 = em.find(Memo.class, 1);
        System.out.println("memo1 ์กฐํšŒ ํ›„ ์บ์‹œ ์ €์žฅ์†Œ์— ์ €์žฅ\n");

        Memo memo2 = em.find(Memo.class, 1);
        System.out.println("memo2.getId() = " + memo2.getId());
        System.out.println("memo2.getUsername() = " + memo2.getUsername());
        System.out.println("memo2.getContents() = " + memo2.getContents());


    } catch (Exception ex) {
        ex.printStackTrace();
    } finally {
        em.close();
    }

    emf.close();
}

1๋ฒˆ๋งŒ ์กฐํšŒ ํ›„ ๋ฐ”๋กœ ์บ์‹œ ์ €์žฅ์†Œ์—์„œ ๊ฐ€์ ธ์˜ด

 

1์ฐจ ์บ์‹œ ์‚ฌ์šฉ์˜ ์žฅ์ 

1. DB ์กฐํšŒ ํšŸ์ˆ˜ ์ค„์ž„

2. '1์ฐจ ์บ์‹œ'๋ฅผ ์‚ฌ์šฉํ•ด DB row 1๊ฐœ ๋‹น ๊ฐ์ฒด 1๊ฐœ๊ฐ€ ์‚ฌ์šฉ๋˜๋Š” ๊ฒƒ์„ ๋ณด์žฅ(๊ฐ์ฒด ๋™์ผ์„ฑ ๋ณด์žฅ)

@Test
@DisplayName("๊ฐ์ฒด ๋™์ผ์„ฑ ๋ณด์žฅ")
void test4() {
    EntityTransaction et = em.getTransaction();

    et.begin();
    
    try {
        Memo memo3 = new Memo();
        memo3.setId(2L);
        memo3.setUsername("Robbert");
        memo3.setContents("๊ฐ์ฒด ๋™์ผ์„ฑ ๋ณด์žฅ");
        em.persist(memo3);

        Memo memo1 = em.find(Memo.class, 1);
        Memo memo2 = em.find(Memo.class, 1);
        Memo memo  = em.find(Memo.class, 2);

        System.out.println(memo1 == memo2);
        System.out.println(memo1 == memo);

        et.commit();
    } catch (Exception ex) {
        ex.printStackTrace();
        et.rollback();
    } finally {
        em.close();
    }

    emf.close();
}

๊ฐ์ฒด ๋™์ผ์„ฑ ํ™•์ธ

 

Entity ์‚ญ์ œ

1. ์‚ญ์ œํ•  Entity๋ฅผ ์กฐํšŒํ•œ ํ›„ ์บ์‹œ ์ €์žฅ์†Œ์— ์—†๋‹ค๋ฉด DB์— ์กฐํšŒํ•ด์„œ ์ €์žฅํ•จ

2. em.remove(entity);

  • em.remove(entity); ํ˜ธ์ถœ ์‹œ ์‚ญ์ œํ•  Entity๋ฅผ DELETED ์ƒํƒœ๋กœ ๋งŒ๋“  ํ›„ ํŠธ๋žœ์žญ์…˜ commit ํ›„ Delete SQL์ด DB์— ์š”์ฒญ๋จ
@Test
@DisplayName("Entity ์‚ญ์ œ")
void test5() {
    EntityTransaction et = em.getTransaction();

    et.begin();

    try {

        Memo memo = em.find(Memo.class, 2);

        em.remove(memo);

        et.commit();

    } catch (Exception ex) {
        ex.printStackTrace();
        et.rollback();
    } finally {
        em.close();
    }

    emf.close();
}

 

๊ธฐ๋Šฅ 2) ์“ฐ๊ธฐ ์ง€์—ฐ ์ €์žฅ์†Œ(ActionQueue)

์“ฐ๊ธฐ ์ง€์—ฐ ์ €์žฅ์†Œ

JPA๊ฐ€ ํŠธ๋žœ์žญ์…˜์ฒ˜๋Ÿผ SQL์„ ๋ชจ์•„์„œ ํ•œ ๋ฒˆ์— DB์— ๋ฐ˜์˜ํ•˜๋Š”๋ฐ, ์ด๋ฅผ ๊ตฌํ˜„ํ•˜๊ธฐ ์œ„ํ•ด ์“ฐ๊ธฐ ์ง€์—ฐ ์ €์žฅ์†Œ๋ฅผ ๋งŒ๋“ค์–ด SQL์„ ๋ชจ์•„๋‘๊ณ  ์žˆ๋‹ค๊ฐ€ ํŠธ๋žœ์žญ์…˜ commit ํ›„ ํ•œ ๋ฒˆ์— DB์— ๋ฐ˜์˜ํ•จ

@Test
@DisplayName("์“ฐ๊ธฐ ์ง€์—ฐ ์ €์žฅ์†Œ ํ™•์ธ")
void test6() {
    EntityTransaction et = em.getTransaction();

    et.begin();

    try {
        Memo memo = new Memo();
        memo.setId(2L);
        memo.setUsername("Robbert");
        memo.setContents("์“ฐ๊ธฐ ์ง€์—ฐ ์ €์žฅ์†Œ");
        em.persist(memo);

        Memo memo2 = new Memo();
        memo2.setId(3L);
        memo2.setUsername("Bob");
        memo2.setContents("๊ณผ์—ฐ ์ €์žฅ์„ ์ž˜ ํ•˜๊ณ  ์žˆ์„๊นŒ?");
        em.persist(memo2);

        System.out.println("ํŠธ๋žœ์žญ์…˜ commit ์ „");
        et.commit();
        System.out.println("ํŠธ๋žœ์žญ์…˜ commit ํ›„");

    } catch (Exception ex) {
        ex.printStackTrace();
        et.rollback();
    } finally {
        em.close();
    }

    emf.close();
}

๋””๋ฒ„๊น…

flush()

  • et.commit(); ํ•˜๋ฉด commit์ด ๋˜๊ณ  ์“ฐ๊ธฐ ์ง€์—ฐ ์ €์žฅ์†Œ์— ์žˆ๋˜ SQL๋“ค์ด ํ•œ ๋ฒˆ์— ์š”์ฒญ์ด ๋จ
  • ํŠธ๋žœ์žญ์…˜ commit์ด ๋œ ๋‹ค์Œ์— ์ถ”๊ฐ€์ ์ธ ๋™์ž‘์ด em.flush();์ž„. ์ฆ‰, flush method ํ˜ธ์ถœ
  • flush method๋Š” ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ์˜ ๋ณ€๊ฒฝ ๋‚ด์šฉ๋“ค์„ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์— ๋ฐ˜์˜ํ•˜๋Š” ์—ญํ•  ์ˆ˜ํ–‰
  • ์ฆ‰, ์“ฐ๊ธฐ ์ง€์—ฐ ์ €์žฅ์†Œ(actionQueue)์˜ SQL๋“ค์„ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์— ์š”์ฒญ์„ ํ•ด์ฃผ๋Š” ๋ฉ”์„œ๋“œ
@Test
@DisplayName("flush() ๋ฉ”์„œ๋“œ ํ™•์ธ")
void test7() {
    EntityTransaction et = em.getTransaction();

    et.begin();

    try {
        Memo memo = new Memo();
        memo.setId(4L);
        memo.setUsername("Flush");
        memo.setContents("Flush() ๋ฉ”์„œ๋“œ ํ˜ธ์ถœ");
        em.persist(memo);

        System.out.println("flush() ์ „");
        em.flush(); // flush() ์ง์ ‘ ํ˜ธ์ถœ
        System.out.println("flush() ํ›„\n");
        

        System.out.println("ํŠธ๋žœ์žญ์…˜ commit ์ „");
        et.commit();
        System.out.println("ํŠธ๋žœ์žญ์…˜ commit ํ›„");

    } catch (Exception ex) {
        ex.printStackTrace();
        et.rollback();
    } finally {
        em.close();
    }

    emf.close();
}

 

โญ๏ธInsert, Update, Delete์™€ ๊ฐ™์ด ๋ฐ์ดํ„ฐ๋ฅผ ๋ณ€๊ฒฝํ•˜๋Š” SQL์„ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์— ์š”์ฒญ ๋ฐ ๋ฐ˜์˜ํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” ํŠธ๋žœ์žญ์…˜ ํ™˜๊ฒฝ์ด ๋ฐ˜๋“œ์‹œ ํ•„์š”ํ•จ!

๊ธฐ๋Šฅ 3) ๋ณ€๊ฒฝ ๊ฐ์ง€(Dirty Checking)

  • ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ์— ์ €์žฅ๋œ Entity๊ฐ€ ๋ณ€๊ฒฝ๋  ๋•Œ๋งˆ๋‹ค Update SQL์ด ์“ฐ๊ธฐ ์ง€์—ฐ ์ €์žฅ์†Œ์— ์ €์žฅ๋œ๋‹ค๋ฉด,
    ํ•˜๋‚˜์˜ Update SQL๋กœ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ๋Š” ์ƒํ™ฉ์„ ์—ฌ๋Ÿฌ๋ฒˆ Update SQL์„ ์š”์ฒญํ•˜๊ฒŒ ๋˜๊ธฐ ๋•Œ๋ฌธ์— ๋น„ํšจ์œจ์ ์ž„

๋ณ€๊ฒฝ ๊ฐ์ง€

  • JPA๋Š” ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ์— Entity๋ฅผ ์ €์žฅํ•  ๋•Œ ์ตœ์ดˆ ์ƒํƒœ(LoadedState)๋ฅผ ์ €์žฅํ•จ
  • ํŠธ๋žœ์žญ์…˜์ด commit๋˜๊ณ  em.flush();๊ฐ€ ํ˜ธ์ถœ๋˜๋ฉด Entity์˜ ํ˜„์žฌ ์ƒํƒœ์™€ ์ €์žฅํ•œ ์ตœ์ดˆ ์ƒํƒœ๋ฅผ ๋น„๊ตํ•จ
  • ๋ณ€๊ฒฝ ๋‚ด์šฉ์ด ์žˆ๋‹ค๋ฉด Update SQL์„ ์ƒ์„ฑํ•ด ์“ฐ๊ธฐ ์ง€์—ฐ ์ €์žฅ์†Œ์— ์ €์žฅํ•˜๊ณ  ๋ชจ๋“  ์“ฐ๊ธฐ์ง€์—ฐ ์ €์žฅ์†Œ์˜ SQL์„ DB์— ์š”์ฒญํ•จ
  • ๋งˆ์ง€๋ง‰์œผ๋กœ DB ํŠธ๋žœ์žญ์…˜์ด commit๋˜๋ฉด์„œ ๋ฐ˜์˜๋จ
  • ์ฆ‰, ๋ณ€๊ฒฝํ•˜๊ณ  ์‹ถ์€ ๋ฐ์ดํ„ฐ๊ฐ€ ์žˆ๋‹ค๋ฉด ๋จผ์ € ๋ฐ์ดํ„ฐ๋ฅผ ์กฐํšŒํ•˜๊ณ  ํ•ด๋‹น Entity ๊ฐ์ฒด์˜ ๋ฐ์ดํ„ฐ๋ฅผ ๋ณ€๊ฒฝํ•˜๋ฉด ์ž๋™์œผ๋กœ Update SQL์ด ์ƒ์„ฑ๋˜๊ณ  DB์— ๋ฐ˜์˜๋จ → ์ด๋Ÿฌํ•œ ๊ณผ์ •์„ ๋ณ€๊ฒฝ ๊ฐ์ง€, Dirty Checking์ด๋ผ๊ณ  ๋ถ€๋ฆ„
@Test
@DisplayName("๋ณ€๊ฒฝ ๊ฐ์ง€ ํ™•์ธ")
void test8() {
    EntityTransaction et = em.getTransaction();

    et.begin();

    try {
        System.out.println("๋ณ€๊ฒฝํ•  ๋ฐ์ดํ„ฐ๋ฅผ ์กฐํšŒํ•ฉ๋‹ˆ๋‹ค.");
        Memo memo = em.find(Memo.class, 4);
        System.out.println("memo.getId() = " + memo.getId());
        System.out.println("memo.getUsername() = " + memo.getUsername());
        System.out.println("memo.getContents() = " + memo.getContents());

        System.out.println("\n์ˆ˜์ •์„ ์ง„ํ–‰ํ•ฉ๋‹ˆ๋‹ค.");
        memo.setUsername("Update");
        memo.setContents("๋ณ€๊ฒฝ ๊ฐ์ง€ ํ™•์ธ");

        System.out.println("ํŠธ๋žœ์žญ์…˜ commit ์ „");
        et.commit();
        System.out.println("ํŠธ๋žœ์žญ์…˜ commit ํ›„");

    } catch (Exception ex) {
        ex.printStackTrace();
        et.rollback();
    } finally {
        em.close();
    }

    emf.close();
}

 

๋ณ€๊ฒฝํ•  ๋‚ด์šฉ์ด ์—†๋‹ค๋ฉด DB ์ ‘๊ทผ X(์˜ˆ์‹œ: ์˜ค๋ฅธ์ชฝ ์‚ฌ์ง„)


Entity์˜ ์ƒํƒœ

Entity ์ƒํƒœ

์˜์†์„ฑ๊ณผ ๋น„์˜์†์„ฑ

๋น„์˜์†์„ฑ ์ƒํƒœ: ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ ์ฆ‰ JPA๊ฐ€ ๊ด€๋ฆฌํ•˜๊ณ  ์žˆ๋Š” ์—”ํ‹ฐํ‹ฐ๊ฐ€ ์•„๋‹Œ ์ˆœ์ˆ˜ํ•œ Entity Class ์ƒํƒœ

  • persist method์˜ ํŒŒ๋ผ๋ฏธํ„ฐ๋กœ Entity Class ๊ฐ์ฒด๋ฅผ ๋˜์ ธ์„œ ์˜์† ์ƒํƒœ๋กœ ๋งŒ๋“ฆ
import com.sparta.entity.Memo;
import jakarta.persistence.EntityManager;
import jakarta.persistence.EntityManagerFactory;
import jakarta.persistence.EntityTransaction;
import jakarta.persistence.Persistence;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;

public class EntityStateTest {
    EntityManagerFactory emf;
    EntityManager em;

    @BeforeEach
    void setUp() {
        emf = Persistence.createEntityManagerFactory("memo");
        em = emf.createEntityManager();
    }

    @Test
    @DisplayName("๋น„์˜์†๊ณผ ์˜์† ์ƒํƒœ")
    void test1() {
        EntityTransaction et = em.getTransaction();

        et.begin();

        try {

            Memo memo = new Memo(); // ๋น„์˜์† ์ƒํƒœ
            memo.setId(1L);
            memo.setUsername("Robbie");
            memo.setContents("๋น„์˜์†๊ณผ ์˜์† ์ƒํƒœ");

            // ๊ด€๋ฆฌ๋˜๊ฒŒ ํ•˜๊ณ  ์‹ถ์€ Entity Class ๊ฐ์ฒด๋ฅผ persist method์˜ ํŒŒ๋ผ๋ฏธํ„ฐ๋กœ ๋˜์ ธ์„œ ํ˜ธ์ถœํ•˜๋ฉด
            // ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ์— ์ €์žฅ๋จ
            em.persist(memo); // ๋น„์˜์† ์ƒํƒœ์˜ Entity → ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ์— ์ €์žฅ → ์˜์† ์ƒํƒœ์˜ Entity

            et.commit();

        } catch (Exception ex) {
            ex.printStackTrace();
            et.rollback();
        } finally {
            em.close();
        }

        emf.close();
    }
}

์ค€์˜์†(Detached)

์˜์†์„ฑ ์ปจํ…์ŠคํŠธ์— ์ €์žฅ๋˜์–ด ๊ด€๋ฆฌ๋˜๋‹ค๊ฐ€ ๋ถ„๋ฆฌ๋œ ์ƒํƒœ

 

์˜์† ์ƒํƒœ → ์ค€์˜์† ์ƒํƒœ 3๊ฐ€์ง€ ๋ฐฉ๋ฒ•

1. detach(entity): ํŠน์ • Entity๋ฅผ ์ค€์˜์† ์ƒํƒœ๋กœ ์ „ํ™˜ํ•ด์คŒ

@Test
@DisplayName("์ค€์˜์† ์ƒํƒœ : detach()")
void test2() {
    EntityTransaction et = em.getTransaction();

    et.begin();

    try {

        Memo memo = em.find(Memo.class, 1);
        System.out.println("memo.getId() = " + memo.getId());
        System.out.println("memo.getUsername() = " + memo.getUsername());
        System.out.println("memo.getContents() = " + memo.getContents());

        // em.contains(entity) : Entity ๊ฐ์ฒด๊ฐ€ ํ˜„์žฌ ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ์— ์ €์žฅ๋˜์–ด ๊ด€๋ฆฌ๋˜๋Š” ์ƒํƒœ์ธ์ง€ ํ™•์ธํ•˜๋Š” ๋ฉ”์„œ๋“œ
        System.out.println("em.contains(memo) = " + em.contains(memo));

        System.out.println("detach() ํ˜ธ์ถœ");
        em.detach(memo);
        System.out.println("em.contains(memo) = " + em.contains(memo));

        System.out.println("memo Entity ๊ฐ์ฒด ์ˆ˜์ • ์‹œ๋„");
        memo.setUsername("Update");
        memo.setContents("memo Entity Update");

        System.out.println("ํŠธ๋žœ์žญ์…˜ commit ์ „");
        et.commit();
        System.out.println("ํŠธ๋žœ์žญ์…˜ commit ํ›„");

    } catch (Exception ex) {
        ex.printStackTrace();
        et.rollback();
    } finally {
        em.close();
    }

    emf.close();
}

detach() ๋ฉ”์„œ๋“œ ํ˜ธ์ถœ ํ›„ ๋ณ€ํ™”
์‹คํ–‰ ๊ฒฐ๊ณผ

  • ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ์— ์˜ํ•ด์„œ ๊ด€๋ฆฌ๋˜๊ณ  ์žˆ๋Š” Entity Class๋ฅผ ์ˆ˜์ •ํ–ˆ์„ ๋•Œ ๋ณ€๊ฒฝ ๊ฐ์ง€๊ฐ€ ์ด๋ฃจ์–ด์ง€์ง€๋งŒ,
    detach() ํ˜ธ์ถœํ•ด์„œ ๋” ์ด์ƒ ๊ด€๋ฆฌ๋˜์ง€ ์•Š๋Š” Entity Class๋Š” ๋ณ€๊ฒฝ ๊ฐ์ง€๊ฐ€ ์ด๋ฃจ์–ด์ง€์ง€ ์•Š์Œ

2. clear(): ์ปจํ…์ŠคํŠธ๋ฅผ ์™„์ „ํžˆ ์ดˆ๊ธฐํ™”ํ•จ. ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ์— ๋“ค์–ด์žˆ๋˜ ๋ชจ๋“  Entity๋ฅผ ์ „๋ถ€ ์ค€์˜์† ์ƒํƒœ๋กœ ์ „ํ™˜ํ•จ

  • ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ์˜ ํ‹€์€ ์œ ์ง€ํ•จ(๋‚ด์šฉ๋งŒ ๋น„์›Œ์ง„ ์ƒˆ๋กœ์šด ์ƒํƒœ๋กœ ๋งŒ๋“ฆ)
@Test
@DisplayName("์ค€์˜์† ์ƒํƒœ : clear()")
void test3() {
    EntityTransaction et = em.getTransaction();

    et.begin();

    try {

        Memo memo1 = em.find(Memo.class, 1);
        Memo memo2 = em.find(Memo.class, 2);

        // em.contains(entity) : Entity ๊ฐ์ฒด๊ฐ€ ํ˜„์žฌ ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ์— ์ €์žฅ๋˜์–ด ๊ด€๋ฆฌ๋˜๋Š” ์ƒํƒœ์ธ์ง€ ํ™•์ธํ•˜๋Š” ๋ฉ”์„œ๋“œ
        System.out.println("em.contains(memo1) = " + em.contains(memo1));
        System.out.println("em.contains(memo2) = " + em.contains(memo2));

        System.out.println("clear() ํ˜ธ์ถœ");
        em.clear();
        System.out.println("em.contains(memo1) = " + em.contains(memo1));
        System.out.println("em.contains(memo2) = " + em.contains(memo2));

        System.out.println("memo#1 Entity ๋‹ค์‹œ ์กฐํšŒ");
        Memo memo = em.find(Memo.class, 1);
        System.out.println("em.contains(memo) = " + em.contains(memo));
        System.out.println("\n memo Entity ์ˆ˜์ • ์‹œ๋„");
        memo.setUsername("Update");
        memo.setContents("memo Entity Update");

        System.out.println("ํŠธ๋žœ์žญ์…˜ commit ์ „");
        et.commit();
        System.out.println("ํŠธ๋žœ์žญ์…˜ commit ํ›„");

    } catch (Exception ex) {
        ex.printStackTrace();
        et.rollback();
    } finally {
        em.close();
    }

    emf.close();
}

clear() ํ˜ธ์ถœ ํ›„ ๋ณ€ํ™”
๊ฒฐ๊ณผ

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

  • ํ•ด๋‹น ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ๊ฐ€ ๊ด€๋ฆฌํ•˜๋˜ ์˜์†์„ฑ ์ƒํƒœ์˜ Entity๋“ค์„ ๋ชจ๋‘ ์ค€์˜์† ์ƒํƒœ๋กœ ๋ณ€๊ฒฝ
  • ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ๊ฐ€ ์ข…๋ฃŒ๋˜์—ˆ๊ธฐ ๋•Œ๋ฌธ์— ๊ณ„์†ํ•ด์„œ ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ ์‚ฌ์šฉํ•  ์ˆ˜ ์—†์Œ
@Test
@DisplayName("์ค€์˜์† ์ƒํƒœ : close()")
void test4() {
    EntityTransaction et = em.getTransaction();

    et.begin();

    try {

        Memo memo1 = em.find(Memo.class, 1);
        Memo memo2 = em.find(Memo.class, 2);

        // em.contains(entity) : Entity ๊ฐ์ฒด๊ฐ€ ํ˜„์žฌ ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ์— ์ €์žฅ๋˜์–ด ๊ด€๋ฆฌ๋˜๋Š” ์ƒํƒœ์ธ์ง€ ํ™•์ธํ•˜๋Š” ๋ฉ”์„œ๋“œ
        System.out.println("em.contains(memo1) = " + em.contains(memo1));
        System.out.println("em.contains(memo2) = " + em.contains(memo2));

        System.out.println("close() ํ˜ธ์ถœ");
        em.close();
        Memo memo = em.find(Memo.class, 2); // Session/EntityManager is closed ๋ฉ”์‹œ์ง€์™€ ํ•จ๊ป˜ ์˜ค๋ฅ˜ ๋ฐœ์ƒ
        System.out.println("memo.getId() = " + memo.getId());

    } catch (Exception ex) {
        ex.printStackTrace();
        et.rollback();
    } finally {
        em.close();
    }

    emf.close();
}

์‹คํ–‰ ๊ฒฐ๊ณผ

 

์ค€์˜์† ์ƒํƒœ → ์˜์† ์ƒํƒœ ๋ฐฉ๋ฒ•

merge(entity): ์ „๋‹ฌ๋ฐ›์€ Entity๋ฅผ ์‚ฌ์šฉํ•ด ์ƒˆ๋กœ์šด ์˜์† ์ƒํƒœ์˜ Entity๋ฅผ ๋ฐ˜ํ™˜ํ•จ

merge(entity) ๋™์ž‘) ํŒŒ๋ผ๋ฏธํ„ฐ๋กœ ์ „๋‹ฌ๋œ Entity์˜ ์‹๋ณ„์ž ๊ฐ’์œผ๋กœ ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ ์กฐํšŒ

  • ํ•ด๋‹น Entity๊ฐ€ ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ์— ์—†๋‹ค๋ฉด,
    • DB์—์„œ ์ƒˆ๋กญ๊ฒŒ ์กฐํšŒ
    • ์กฐํšŒํ•œ Entity๋ฅผ ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ์— ์ €์žฅ
    • ์ „๋‹ฌ๋ฐ›์€ Entity์˜ ๊ฐ’์„ ์‚ฌ์šฉํ•ด ๋ณ‘ํ•ฉ
    • Update SQL์ด ์ˆ˜ํ–‰(์ˆ˜์ •)
  • ๋งŒ์•ฝ DB์—๋„ ์—†๋‹ค๋ฉด,
    • ์ƒˆ๋กญ๊ฒŒ ์ƒ์„ฑํ•œ Entity๋ฅผ ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ์— ์ €์žฅ
    • Insert SQL์ด ์ˆ˜ํ–‰(์ €์žฅ)

๋”ฐ๋ผ์„œ merge(entity)๋Š” ๋น„์˜์†, ์ค€์˜์† ๋ชจ๋‘ ํŒŒ๋ผ๋ฏธํ„ฐ๋กœ ๋ฐ›์„ ์ˆ˜ ์žˆ์œผ๋ฉฐ ์ƒํ™ฉ์— ๋”ฐ๋ผ ์ €์žฅ ํ˜น์€ ์ˆ˜์ •ํ•  ์ˆ˜ ์žˆ์Œ

 

1. merge(entity) ์ €์žฅ

@Test
@DisplayName("merge() : ์ €์žฅ")
void test5() {
    EntityTransaction et = em.getTransaction();

    et.begin();

    try {

        Memo memo = new Memo();
        memo.setId(3L);
        memo.setUsername("merge()");
        memo.setContents("merge() ์ €์žฅ");

        System.out.println("merge() ํ˜ธ์ถœ");
        Memo mergedMemo = em.merge(memo);

        System.out.println("em.contains(memo) = " + em.contains(memo));
        System.out.println("em.contains(mergedMemo) = " + em.contains(mergedMemo));

        System.out.println("ํŠธ๋žœ์žญ์…˜ commit ์ „");
        et.commit();
        System.out.println("ํŠธ๋žœ์žญ์…˜ commit ํ›„");

    } catch (Exception ex) {
        ex.printStackTrace();
        et.rollback();
    } finally {
        em.close();
    }

    emf.close();
}

Insertion ์ˆ˜ํ–‰

2. merge(entity) ์ˆ˜์ •

@Test
@DisplayName("merge() : ์ˆ˜์ •")
void test6() {
    EntityTransaction et = em.getTransaction();

    et.begin();

    try {

        Memo memo = em.find(Memo.class, 3);
        System.out.println("memo.getId() = " + memo.getId());
        System.out.println("memo.getUsername() = " + memo.getUsername());
        System.out.println("memo.getContents() = " + memo.getContents());

        System.out.println("em.contains(memo) = " + em.contains(memo));

        System.out.println("detach() ํ˜ธ์ถœ");
        em.detach(memo); // ์ค€์˜์† ์ƒํƒœ๋กœ ์ „ํ™˜
        System.out.println("em.contains(memo) = " + em.contains(memo));

        System.out.println("์ค€์˜์† memo ๊ฐ’ ์ˆ˜์ •");
        memo.setContents("merge() ์ˆ˜์ •");

        System.out.println("\n merge() ํ˜ธ์ถœ");
        Memo mergedMemo = em.merge(memo);
        System.out.println("mergedMemo.getContents() = " + mergedMemo.getContents());

        System.out.println("em.contains(memo) = " + em.contains(memo));
        System.out.println("em.contains(mergedMemo) = " + em.contains(mergedMemo));

        System.out.println("ํŠธ๋žœ์žญ์…˜ commit ์ „");
        et.commit();
        System.out.println("ํŠธ๋žœ์žญ์…˜ commit ํ›„");

    } catch (Exception ex) {
        ex.printStackTrace();
        et.rollback();
    } finally {
        em.close();
    }

    emf.close();
}

๊ฒฐ๊ณผ