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 ์์ ์ ์ค์ฌ์ฃผ๊ธฐ ์ํด ๋ฑ์ฅ

JPA(Java Persistence API)
Java ORM ๊ธฐ์ ์ ๋ํ์ ์ธ ํ์ค ๋ช ์ธ


Hibernate: JPA๋ฅผ ์ค์ ๋ก ๊ตฌํํ ํ๋ ์์ํฌ
Entity ์ดํดํ๊ธฐ
Entity๋ JPA์์ ๊ด๋ฆฌ๋๊ณ ์๋ Class, ์ฆ ๊ฐ์ฒด๋ฅผ ์๋ฏธํจ.
Entity Class๋ ๋ฐ์ดํฐ๋ฒ ์ด์ค์ table๊ณผ ๋งตํ์ด ๋์ด์ JPA์ ์ํด์ ๊ด๋ฆฌ๋๊ณ ์์

Java ํ๊ฒฝ์์ JPA ์ฌ์ฉํ๊ธฐ
1. persistence.xml ํ์ผ๊ณผ build.gradle ํ์ผ ์์

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๋ฅผ ๊ด๋ฆฌํ๋ ๊ด๋ฆฌ์

- ๊ฐ๋ฐ์๋ค์ EntityManager๋ฅผ ์ฌ์ฉํด Entity๋ฅผ ์ ์ฅํ๊ณ ์กฐํํ๊ณ ์์ ํ๊ณ ์ญ์ ํ ์ ์์
- EntityManager๋ 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์ ์์ฒญํด ๋ณ๊ฒฝ์ ๋ฐ์ํจ

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 ๋ฅผ ์ข
๋ฃํฉ๋๋ค.
}
}

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์ฐจ ์บ์
์์์ฑ ์ปจํ ์คํธ๋ ๋ด๋ถ์ ์ผ๋ก ์บ์ ์ ์ฅ์๋ฅผ ๊ฐ์ง๊ณ ์์

- ์ ์ฅํ๋ Entity ๊ฐ์ฒด๋ค์ด 1์ฐจ ์บ์ ์ฆ, ์บ์ ์ ์ฅ์์ ์ ์ฅ๋จ
- ์บ์ ์ ์ฅ์๋ Map ์๋ฃ๊ตฌ์กฐ ํํ๋ก ๋์ด์์
- key์๋ @Id๋ก ๋งคํํ ๊ธฐ๋ณธ ํค์ธ ์๋ณ์ ๊ฐ์ ์ ์ฅํจ
- value์๋ ํด๋น Entity ํด๋์ค์ ๊ฐ์ฒด๋ฅผ ์ ์ฅํจ
- ์์์ฑ ์ปจํ ์คํธ๋ ์บ์ ์ ์ฅ์ Key์ ์ ์ฅํ ์๋ณ์๊ฐ์ ์ฌ์ฉํด 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();
}


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. 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์ ์ํ

์์์ฑ๊ณผ ๋น์์์ฑ
๋น์์์ฑ ์ํ: ์์์ฑ ์ปจํ ์คํธ ์ฆ 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();
}



- ์์์ฑ ์ปจํ
์คํธ์ ์ํด์ ๊ด๋ฆฌ๋๊ณ ์๋ 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();
}



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


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

'๋ฐฑ์๋ > spring&springboot' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
| [๋ด์ผ๋ฐฐ์์บ ํ_Spring Boot ์๋ จ์ฃผ์ฐจ] Bean (0) | 2026.06.26 |
|---|---|
| [๋ด์ผ๋ฐฐ์์บ ํ_Spring Boot ์ ๋ฌธ์ฃผ์ฐจ] Spring Data JPA (0) | 2026.06.26 |
| [๋ด์ผ๋ฐฐ์์บ ํ_Spring Boot ์ ๋ฌธ์ฃผ์ฐจ] IoC์ DI (1) | 2026.06.25 |
| [๋ด์ผ๋ฐฐ์์บ ํ_Spring Boot ์ ๋ฌธ์ฃผ์ฐจ] 3 Layer Architecture (0) | 2026.06.25 |
| [๋ด์ผ๋ฐฐ์์บ ํ_Spring Boot ์ ๋ฌธ์ฃผ์ฐจ] Database์ SQL (0) | 2026.06.24 |