[LG U+ ์œ ๋ ˆ์นด 3๊ธฐ]์ˆœ์ˆ˜ JPA ์‹ค์Šต ์—”ํ‹ฐํ‹ฐ ์ƒ๋ช…์ฃผ๊ธฐ (persist / find / merge / detach / remove)

2025. 10. 20. 11:51ใ†Java/JPA

๐Ÿงฉ JPA ์‹ค์Šต โ‘ข — ์—”ํ‹ฐํ‹ฐ ์ƒ๋ช…์ฃผ๊ธฐ (persist / find / merge / detach / remove)

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


โถ ์‹ค์Šต ๋ชฉํ‘œ

  • persist() : ์ƒˆ๋กœ์šด ๊ฐ์ฒด๋ฅผ ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ์— ๋“ฑ๋ก
  • find() : DB ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ์ฒดํ™”ํ•˜์—ฌ 1์ฐจ ์บ์‹œ์— ์ €์žฅ
  • merge() : ์กด์žฌํ•˜๋ฉด update, ์—†์œผ๋ฉด insert ์ˆ˜ํ–‰
  • detach() : ์—”ํ‹ฐํ‹ฐ๋ฅผ ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ์—์„œ ๋ถ„๋ฆฌ
  • remove() : ์—”ํ‹ฐํ‹ฐ ์‚ญ์ œ (1์ฐจ ์บ์‹œ ๋ฐ DB ๋ฐ˜์˜)

โท ์ฝ”๋“œ ๊ตฌ์„ฑ


src/main/java/
 โ”œโ”€ config/MyPersistenceUnitInfo.java
 โ”œโ”€ entity/Employee.java
 โ””โ”€ Test.java

๐Ÿ“„ Employee.java


package entity;

import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.Id;
import jakarta.persistence.Table;

@Entity
// @Table(name = "emp")
public class Employee {
	@Id
//  @Column(name="emp_id")
	private int id;
	
	private String name;
	private String address;
	
	
	public int getId() {
		return id;
	}
	public void setId(int id) {
		this.id = id;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public String getAddress() {
		return address;
	}
	public void setAddress(String address) {
		this.address = address;
	}
	@Override
	public String toString() {
		return "Employee [id=" + id + ", name=" + name + ", address=" + address + "]";
	}
}

@Table / @Column ์–ด๋…ธํ…Œ์ด์…˜ ๊ฐ„๋‹จ ์ •๋ฆฌ

์—”ํ‹ฐํ‹ฐ ํด๋ž˜์Šค์˜ ํ…Œ์ด๋ธ”๋ช…๊ณผ ์ปฌ๋Ÿผ๋ช…์„ DB์™€ ๋‹ค๋ฅด๊ฒŒ ์ง€์ •ํ•˜๊ณ  ์‹ถ์„ ๋•Œ ์‚ฌ์šฉํ•˜๋Š” ๋งคํ•‘ ์–ด๋…ธํ…Œ์ด์…˜์ด๋‹ค.

๊ฐ„๋‹จํ•œ ์–ด๋…ธํ…Œ์ด์…˜ ์‹ค์Šต๋„ ์ง„ํ–‰ํ•˜๊ธฐ์œ„ํ•ด ๊ธฐ์กด์˜ employeeํ…Œ์ด๋ธ”๊ณผ ๋˜‘๊ฐ™์€ ํ…Œ์ด๋ธ”์ธ empํ…Œ์ด๋ธ”์„ ๋งŒ๋“ค์–ด์ค€๋’ค ์‹ค์Šต์ง„ํ–‰ํ•จ.

โœ… @Table

  • ํด๋ž˜์Šค ๋ ˆ๋ฒจ์—์„œ ์‚ฌ์šฉ๋œ๋‹ค.
  • DB์˜ ์‹ค์ œ ํ…Œ์ด๋ธ” ์ด๋ฆ„์„ ์ง€์ •ํ•œ๋‹ค.

@Entity
@Table(name = "emp")  // ์‹ค์ œ ํ…Œ์ด๋ธ”๋ช…์„ emp๋กœ ์ง€์ •
public class Employee { ... }

๐Ÿ‘‰ ์ƒ๋žต ์‹œ ํด๋ž˜์Šค๋ช…(Employee)์ด ํ…Œ์ด๋ธ”๋ช…์œผ๋กœ ์ž๋™ ๋งคํ•‘๋œ๋‹ค.


โœ… @Column

  • ํ•„๋“œ(์†์„ฑ) ๋‹จ์œ„๋กœ ์‚ฌ์šฉ๋œ๋‹ค.
  • DB์˜ ์‹ค์ œ ์ปฌ๋Ÿผ ์ด๋ฆ„, ๊ธธ์ด, ์ œ์•ฝ ์กฐ๊ฑด ๋“ฑ์„ ์ง€์ •ํ•œ๋‹ค.

@Id
@Column(name = "emp_id", length = 10, nullable = false)
private int id;

์†์„ฑ ์„ค๋ช… ๐Ÿ‘‡

์†์„ฑ๋ช… ์„ค๋ช…
name DB ์ปฌ๋Ÿผ๋ช… ์ง€์ •
length ๋ฌธ์ž์—ด ์ปฌ๋Ÿผ ๊ธธ์ด ์ง€์ • (๊ธฐ๋ณธ 255)
nullable false๋กœ ์„ค์ • ์‹œ NOT NULL ์ œ์•ฝ์กฐ๊ฑด ์ ์šฉ
unique ์œ ๋‹ˆํฌ ์ œ์•ฝ์กฐ๊ฑด ์„ค์ •
insertable / updatable SQL INSERT/UPDATE ์‹œ ํฌํ•จ ์—ฌ๋ถ€ ์ œ์–ด

๐Ÿ’ก ์˜ˆ์‹œ


@Entity
@Table(name = "emp_table")
public class Employee {
    @Id
    @Column(name = "emp_id")
    private int id;

    @Column(name = "emp_name", length = 30)
    private String name;

    @Column(name = "emp_address", nullable = false)
    private String a

๐Ÿ“„ Test.java


import java.util.HashMap;
import config.MyPersistenceUnitInfo;
import entity.Employee;
import jakarta.persistence.EntityManager;
import jakarta.persistence.EntityManagerFactory;
import org.hibernate.jpa.HibernatePersistenceProvider;

public class Test {
    public static void main(String[] args) {
        EntityManagerFactory emf = new HibernatePersistenceProvider()
                .createContainerEntityManagerFactory(new MyPersistenceUnitInfo(), new HashMap<>());

        EntityManager em = emf.createEntityManager();
        em.getTransaction().begin();

        // #1. persist()
        // ์ƒˆ๋กœ์šด ๊ฐ์ฒด๋ฅผ ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ์— ๋“ฑ๋ก (DB insert๋Š” commit ์‹œ์ )
        // Employee e1 = new Employee();
        // e1.setId(1);
        // e1.setName("ํ™๊ธธ๋™");
        // e1.setAddress("์„œ์šธ");
        // em.persist(e1);

        // #2. find()
        // Employee e = em.find(Employee.class, 1);
        // System.out.println(e);
        // e.setAddress("๋Œ€์ „"); // update X
        // System.out.println(e); // commit() ์‹œ์ ์— update O

        // #3. merge()
        // Employee e = new Employee();
        // e.setId(2);
        // e.setName("์ด๊ธธ๋™");
        // e.setAddress("๊ด‘์ฃผ");
        // em.merge(e); // id=2๊ฐ€ ์—†์œผ๋ฉด insert

        // Employee e2 = new Employee();
        // e2.setId(2);
        // e2.setName("์ด๊ธธ๋™");
        // e2.setAddress("๋ถ€์‚ฐ");
        // em.merge(e2); // id=2๊ฐ€ ์กด์žฌํ•˜๋ฉด update

        // #4. detach()
        // Employee e = em.find(Employee.class, 2);
        // System.out.println(e);
        // em.detach(e); // ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ์—์„œ ๋ถ„๋ฆฌ
        // e.setAddress("๊ฐ•๋ฆ‰"); // update X (๋” ์ด์ƒ ๊ด€๋ฆฌ X)
        // System.out.println(e);

        // #5. remove()
        // Employee e = em.find(Employee.class, 2);
        // em.remove(e); // DB์—์„œ ์‚ญ์ œ๋จ (commit ์‹œ์ )
        
        // ์•„๋ž˜๋Š” ์˜ˆ์™ธ ๋ฐœ์ƒ ์˜ˆ์‹œ (๋น„์˜์† ๊ฐ์ฒด remove)
        Employee e = new Employee();
        e.setId(1);
        em.remove(e); // IllegalArgumentException: detached instance

        em.getTransaction().commit();
        em.close();
    }
}

โน ์ฃผ์š” ๋ฉ”์„œ๋“œ๋ณ„ ๋™์ž‘ ์›๋ฆฌ

โœ… โ‘  persist()

  • ์ƒˆ ๊ฐ์ฒด๋ฅผ ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ(1์ฐจ ์บ์‹œ)์— ๋“ฑ๋กํ•œ๋‹ค.
  • DB์— ์ฆ‰์‹œ INSERT ๋˜์ง€ ์•Š๊ณ , commit() ์‹œ์ ์— flush()๋˜๋ฉด์„œ SQL ์‹คํ–‰.

โœ… โ‘ก find()

  • DB ๋ฐ์ดํ„ฐ๋ฅผ ์กฐํšŒํ•ด ๊ฐ์ฒด๋กœ ๋ณ€ํ™˜ ํ›„ 1์ฐจ ์บ์‹œ์— ์ €์žฅํ•œ๋‹ค.
  • ๊ฐ™์€ ID๋กœ ๋‹ค์‹œ find()๋ฅผ ํ˜ธ์ถœํ•˜๋ฉด ์บ์‹œ์—์„œ ๋ฐ˜ํ™˜๋˜์–ด DB ์กฐํšŒ X.

โœ… โ‘ข merge()

  • ๋น„์˜์† ์ƒํƒœ์˜ ์—”ํ‹ฐํ‹ฐ๋ฅผ ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ์— ๋ณ‘ํ•ฉํ•œ๋‹ค.
  • DB์— ์กด์žฌํ•˜์ง€ ์•Š์œผ๋ฉด INSERT, ์กด์žฌํ•˜๋ฉด UPDATE ์ˆ˜ํ–‰.
  • merge()๋Š” ํ•ญ์ƒ ์ƒˆ๋กœ์šด ์˜์† ๊ฐ์ฒด๋ฅผ ๋ฐ˜ํ™˜ํ•œ๋‹ค.

โœ… โ‘ฃ detach()

  • ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ์—์„œ ์—”ํ‹ฐํ‹ฐ๋ฅผ ๋ถ„๋ฆฌ์‹œํ‚จ๋‹ค.
  • ์ดํ›„ ํ•„๋“œ ๋ณ€๊ฒฝ์€ ๊ฐ์ง€๋˜์ง€ ์•Š์œผ๋ฉฐ, commit ์‹œ์ ์— update SQL X.

โœ… โ‘ค remove()

  • ์—”ํ‹ฐํ‹ฐ๋ฅผ ์‚ญ์ œ ์ƒํƒœ๋กœ ํ‘œ์‹œํ•œ๋‹ค.
  • commit ์‹œ์ ์— DELETE SQL ์‹คํ–‰.
  • ๋น„์˜์† ๊ฐ์ฒด๋ฅผ remove()ํ•˜๋ฉด IllegalArgumentException ๋ฐœ์ƒ.

โบ ์˜ˆ์™ธ ์ƒํ™ฉ ์ •๋ฆฌ


1๏ธโƒฃ ๋™์ผํ•œ ID๋กœ persist() → 
java.sql.SQLIntegrityConstraintViolationException: Duplicate entry '1' for key 'PRIMARY'

2๏ธโƒฃ ๋น„์˜์† ๊ฐ์ฒด remove() → 
java.lang.IllegalArgumentException: Removing a detached instance entity.Employee#1

โป ์‹ค์Šต ํ•ต์‹ฌ ์š”์•ฝ

๋ฉ”์„œ๋“œ ์ƒํƒœ ๋ณ€ํ™” DB ๋ฐ˜์˜ ์‹œ์  ๋น„๊ณ 
persist() ๋น„์˜์† → ์˜์† commit() 1์ฐจ ์บ์‹œ์— ๋“ฑ๋ก
find() DB → ์˜์† ์ฆ‰์‹œ (SELECT) 1์ฐจ ์บ์‹œ ์žฌ์‚ฌ์šฉ
merge() ๋น„์˜์† → ์˜์† commit() DB ์—†์œผ๋ฉด insert, ์žˆ์œผ๋ฉด update
detach() ์˜์† → ์ค€์˜์† - ๋” ์ด์ƒ ๊ด€๋ฆฌ๋˜์ง€ ์•Š์Œ
remove() ์˜์† → ์‚ญ์ œ commit() DELETE SQL ์‹คํ–‰

โผ ํ•ต์‹ฌ ํ•œ ์ค„ ์š”์•ฝ

JPA์˜ ์ง„์งœ ๋ณธ์งˆ์€ SQL ์‹คํ–‰๊ธฐ๊ฐ€ ์•„๋‹ˆ๋ผ “์—”ํ‹ฐํ‹ฐ ์ƒํƒœ ๊ด€๋ฆฌ ์‹œ์Šคํ…œ”์ด๋‹ค.
persist()๋กœ ๋“ฑ๋ก๋˜๊ณ , find()๋กœ ์กฐํšŒ๋œ ๊ฐ์ฒด๋Š” ๋ชจ๋‘ JPA๊ฐ€ ๊ฐ์‹œํ•˜๊ณ  ์žˆ๋‹ค.
commit() ์‹œ์ ์— flush() → ๋ณ€๊ฒฝ ๊ฐ์ง€ → SQL ์ƒ์„ฑ → DB ๋ฐ˜์˜์ด ์ผ์–ด๋‚œ๋‹ค.


๐Ÿ“š ์šฉ์–ด ์ •๋ฆฌ

์šฉ์–ด ์„ค๋ช…
์˜์†์„ฑ ์ปจํ…์ŠคํŠธ ์—”ํ‹ฐํ‹ฐ๋ฅผ ์ €์žฅ·๊ด€๋ฆฌํ•˜๋Š” 1์ฐจ ์บ์‹œ ๊ณต๊ฐ„
๋น„์˜์† (Transient) JPA๊ฐ€ ์•„์ง ๊ด€๋ฆฌํ•˜์ง€ ์•Š๋Š” ๋‹จ์ˆœ ๊ฐ์ฒด
์˜์† (Managed) JPA๊ฐ€ ์ถ”์  ์ค‘์ธ ๊ฐ์ฒด (persist, find ๊ฒฐ๊ณผ)
์ค€์˜์† (Detached) ๋” ์ด์ƒ ๊ด€๋ฆฌ๋˜์ง€ ์•Š๋Š” ๊ฐ์ฒด (detach ํ›„)
์‚ญ์ œ (Removed) commit ์‹œ DELETE SQL ์‹คํ–‰ ์˜ˆ์ • ์ƒํƒœ