
@ManyToOne, @OneToMany, @OneToOne, @ManyToManymappedBy μ¬μ© μ λΉμ£ΌμΈ)@JoinColumn μ μΈλ¨)1, λΉμ£ΌμΈμ 리μ€νΈλ₯Ό 컬λ μ
μΌλ‘ 보μ ν΄μΌ ν¨@JoinColumnμΌλ‘ μΈλν€ μ»¬λΌ μ§μ κ°λ₯insertable = false, updatable = falseλ‘ μ½κΈ° μ μ© μ€μ κ°λ₯@ManyToOne
@JoinColumn(name = "company_id", insertable = false, updatable = false)
private Company company;
μΈλ ν€κ° μλ κ³³μ΄ μ°κ΄κ΄κ³μ μ£ΌμΈ (UNIQUE μ¬μ© β)
| μ₯μ | λ¨μ | |
|---|---|---|
| μ£Ό ν μ΄λΈ | μ£Όν μ΄λΈλ§ μ‘°νν΄λ λμ ν μ΄λΈμ μ‘°νν μ μλ€ | null νμ© (λμ ν
μ΄λΈ κ°μ΄ μμλ) μμ μ μΈλ ν€ κ° μ²λ¦¬νμ |
| λμ ν μ΄λΈ | μ°κ΄κ΄κ³ λ³κ²½μμλ ν μ΄λΈ ꡬ쑰 μ μ§ | μ§μ°λ‘λ©μ μ€μ ν΄λ μ¦μ λ‘λ© |
@ManyToManyλ‘ μ€μ κ°λ₯νμ§λ§ μ€λ¬΄μμλ μ§μ
μ°κ΄κ΄κ³ μΆμ² μ€λͺ 1:N λ¨λ°©ν₯ β λΉμΆμ² FKκ° μμμ μλλ° λΆλͺ¨κ° κ΄λ¦¬νλ ꡬ쑰 β λΉν¨μ¨μ N:1 μλ°©ν₯ β μΆμ² κ°μ²΄-DB μΌκ΄μ± μ μ§, κ°μ₯ μμ°μ€λ¬μ΄ ꡬ쑰 1:1 β μ‘°κ±΄λΆ μΆμ² μν©μ λ°λΌ λ¨λ°©ν₯ λλ μλ°©ν₯ μ ν (FK μμΉ κ³ λ €) N:M β λΉμΆμ² μ€κ° ν μ΄λΈμ λ³λ μν°ν°λ‘ λΆλ¦¬νλ λ°©μ μΆμ²
κ΄κ³ν λ°μ΄ν°λ² μ΄μ€μ ν μ΄λΈμλ μμκ΄κ³κ° μμ§λ§
JPAλ₯Ό νμ©ν΄ μμμ²λΌ μ¬μ©ν μ μλ€!
SINGLE_TABLE μ λ΅ (default)@Inheritance(strategy = InheritanceType.SINGLE_TABLE)@DiscriminatorColumn(name = "dtype") β μλ΅ κ°λ₯@DiscriminatorValue("μνλꡬλΆκ°")@DiscriminatorColumnμΌλ‘ κ΅¬λΆ ( μ μΈνμ§ μμλ DTYPEμΌλ‘ μ»¬λΌ μμ±)| μ₯μ | λ¨μ |
|---|---|
| 쿼리 λΉ λ¦ (μ‘°μΈ μμ) | λ¨μΌ ν
μ΄λΈμ΄λ―λ‘ μ»¬λΌμ΄ λ§μμ§κ³ , μμμ΄ λ§€νν 컬λΌμ NULL λ§μμ§ |
| κ΄λ¦¬ μ©μ΄ | DB μ κ·ν X |
@Entity
@Inheritance(strategy = InheritanceType.SINGLE_TABLE) β
@DiscriminatorColumn(name = "dtype") β
public abstract class Item {
@Id @GeneratedValue
private Long id;
private String name;
}
@Entity
@DiscriminatorValue("B") β
public class Book extends Item {
private String author;
}
@Entity
@DiscriminatorValue("M") β
public class Movie extends Item {
private String director;
}
Item book = new Book();
book.setName("JPA Book");
((Book) book).setAuthor("μλ¦°");
em.persist(book); β
item
| id | name | author | director | dtype |
|---|---|---|---|---|
| 1 | JPA Book | μλ¦° | null | B |
JOINED μ λ΅@Inheritance(strategy = InheritanceType.JOINED)@DiscriminatorColumn(name = "dtype") β μλ΅ λΆκ°@DiscriminatorValue("μνλꡬλΆκ°")JOINμ ν΅ν΄ μ‘°ν| μ₯μ | λ¨μ |
|---|---|
| μ κ·ν μλ¨ (DB κΉλ) | μ±λ₯ λλ¦Ό (JOIN λ°μ) |
| μμ ν μ΄λΈλ§λ€ νμν 컬λΌλ§ κ°μ§ | INSERT μ 쿼리 2λ² λ°μ |
@Entity
@Inheritance(strategy = InheritanceType.JOINED) β
@DiscriminatorColumn(name = "dtype") β
public abstract class Item {
@Id @GeneratedValue
private Long id;
private String name;
}
@Entity
@DiscriminatorValue("B") β
public class Book extends Item {
private String author;
}
Book book = new Book();
book.setName("JPA Book");
book.setAuthor("μλ¦°");
em.persist(book); β
item
| id | name | dtype |
|---|---|---|
| 1 | JPA Book | B |
book
| id | author |
|---|---|
| 1 | μλ¦° |
TABLE_PER_CLASS μ λ΅ (μ¬μ© β)@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
β@DiscriminatorColumn, @DiscriminatorValue μ¬μ© μ ν¨
GenerationType.IDENTIFY μ¬μ© λΆκ°| μ₯μ | λ¨μ |
|---|---|
| μμ ν μ΄λΈ μμ λ 립, λΉ λ¦ | 쿼리 볡μ‘, UNION νμ(μμ ν μ΄λΈμ μ λΆ ν©μ³μΌν¨) |
| not null μ¬μ© κ°λ₯ | λΆλͺ¨ κ°μ²΄ νμ μ‘°νμ μμ μ λΆ μ‘°νν΄μΌ ν¨ |
@Entity
@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS) β
public abstract class Item {
@Id @GeneratedValue
private Long id;
private String name;
}
@Entity
public class Book extends Item {
private String author;
}
Book book = new Book();
book.setName("JPA Book");
book.setAuthor("μλ¦°");
em.persist(book); β
book
| id | name | author |
|---|---|---|
| 1 | JPA Book | μλ¦° |
π‘ item ν
μ΄λΈμ μμ! Book, Movie κ°κ° λ
립 ν
μ΄λΈλ‘ μμ±λ¨.
@Inheritance(strategy = InheritanceType.${μ λ΅})
JOINED: μ‘°μΈSINGLE_TABLE: λ¨μΌ ν μ΄λΈ(Default)TABLE_PER_CLASS: ꡬν ν΄λμ€λ§λ€ ν μ΄λΈ
@DiscriminatorColumn(name = "dtype")
dtype컬λΌμ μμ±ν¨ (κ΄λ‘)- μ΄λ¦ λ³κ²½ κ°λ₯
- κΈ°λ³Έ κ°:
DTYPE
@DiscriminatorValue("${κ°}")
dtypeκ° μ§μ - κΈ°λ³Έ κ°: ν΄λμ€ μ΄λ¦
em.getReference()λ νλ‘μ κ°μ²΄λ₯Ό λ°ν

target : μ€μ κ°μ²΄μ μ°Έμ‘°κ°μ 보κ΄== λ‘λ λΉκ΅ λΆκ°, instanceof μ¬μ©)Tutor proxyTutor = em.getReference(Tutor.class, tutor.getId()); β
νλ‘μ κ°μ²΄ μμ± (μ€μ κ°μ²΄μ μ°Έμ‘°κ°λ§ κΈ°μ΅)
System.out.println("proxyTutor.getName() = " + proxyTutor.getName()); β
νλ μ κ·Ό ν μ‘°ν SQL μ€ν (μ΄κΈ°ν)
em.getReference()λ νλ‘μ κ°μ²΄λ₯Ό μμ±detachνκ±°λ, νλ‘μ κ°μ²΄λ₯Ό μμ±νμ§ μκ³ κ°μ²΄μ μ κ·Όνκ³ μ νμλ!| λ©μλ | em.find() | em.getReference() |
|---|---|---|
| DB 쿼리 λ°μ μ¬λΆ | μ‘°κ±΄λΆ β | β β νλ‘μ κ°μ²΄ λ°ν |
| μ€λͺ | 1μ°¨ μΊμ β DB μ‘°ν + μΊμμ μΆκ° | μ€μ DB μ‘°ννμ§ μκ³ νλ‘μ κ°μ²΄λ§ λ±λ‘ |
μ§μ°λ‘λ© μ¦μλ‘λ© fetch = FetchType.LAZY fetch = FetchType.EAGER proxy κ°μ²΄λ₯Ό μ‘°ν proxy μ‘°ν β, μ°κ΄λ κ°μ²΄ νλ²μ μ‘°ν μ°κ΄λ κ°μ²΄λ₯Ό λ§€λ² μ‘°ννλκ² λλΉμΈ κ²½μ° μ°κ΄λ κ°μ²΄λ₯Ό λ§€λ² ν¨κ» μ‘°ννλ κ²μ΄ ν¨μ¨μ μΈ κ²½μ°
@OneToMany(mappedBy = "category", cascade = CascadeType.ALL)
πΌ μΉ΄ν
κ³ λ¦¬-νλ‘λνΈ λ¦¬μ€νΈ κ°μ μμμ± μ μ΄ μ€μ ν¨
private List<Product> productList = new ArrayList<>();
@OneToManyκ° μ μΈλ μͺ½ = λΆλͺ¨ μͺ½μ μ μΈ| βοΈ CascadeType.ALL | βοΈ CascadeType.PERSIST | βοΈ CascadeType.REMOVE |
|---|---|---|
| PERSIST + REMOVE + MERGE + REFRESH + DETACH ... λ± | em.persist(parent) νμ λ β μμλ€λ μλμΌλ‘ persist() | em.remove(parent) νμ λβ μμλ€λ μλμΌλ‘ remove() |
| λͺ¨λ μ μ΄ ν¬ν¨ | INSERT 쿼리 κ°μ΄ λ°μ | DELETE 쿼리 κ°μ΄ λ°μ |
λΆλͺ¨-μμ κ΄κ³κ° λκΈ΄ μμ κ°μ²΄λ₯Ό DBμμ μλμΌλ‘ μμ ν μ§ μ€μ
@OneToManyκ° μ μΈλ μͺ½ = λΆλͺ¨μ μ μΈ
| false (κΈ°λ³Έκ°) | true |
|---|---|
| μμμ DBμ κ·Έλλ‘ λ¨μ (βμλ μμ νμ) | μμμ DELETE 쿼리 λ°μ, DBμμλ μ κ±°λ¨ |
βͺοΈ μν°ν° μ½λ
@Entity
@Table(name = "category")
public class Category {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
@OneToMany(mappedBy = "category", cascade = CascadeType.ALL, orphanRemoval = true) β
private List<Product> productList = new ArrayList<>();
public Category() {
}
...
public void addProduct(Product product) {
productList.add(product);
product.setCategory(this); // μ°κ΄κ΄κ³ μ£ΌμΈ μ€μ μ λ©μλλ‘!
}
}
βͺοΈ μ€ν μ½λ
public class OrphanRemovalMain {
public static void main(String[] args) {
...
try {
// 1. λΆλͺ¨ μμ±
Category category = new Category("food");
// 2. μμ μμ± (μμ§ μ°κ΄κ΄κ³ X)
Product product1 = new Product("pizza");
Product product2 = new Product("kimchi");
// 3. μ°κ΄κ΄κ³ μ€μ (addProductκ° μλ°©ν₯ μ°κ΄κ΄κ³ μ£Όμ
)
category.addProduct(product1);
category.addProduct(product2);
// 4. λΆλͺ¨λ§ persistνμ§λ§, cascade λλΆμ μμλ μλ persistλ¨
em.persist(category); // cascade = ALL
// 5. DBμ λ°μ + μμμ± μ»¨ν
μ€νΈ λΉμ
em.flush(); // INSERT μ€ν
em.clear(); // 1μ°¨ μΊμ μ΄κΈ°ν
// 6. λ€μ λΆλͺ¨ μ‘°ν
Category findCategory = em.find(Category.class, category.getId());
// 7. μμμ 컬λ μ
μμ μ κ±°!
findCategory.getProductList().remove(0);
// β
orphanRemoval = true μ΄λ―λ‘,
// μ¬κΈ°μ "μμ 1κ°κ° λΆλͺ¨μμ μ κ±°λλ€ β κ³ μ κ°μ²΄!" λΌκ³ νλ¨
// β νΈλμμ
μ»€λ° μ DELETE 쿼리 λ λ¦Ό! π₯
transaction.commit(); // β
μ¬κΈ°μ μμ 1κ° DELETE 쿼리 λ°μ
...
}
}
νλͺ© CascadeType.Remove orphanRemoval=true λͺ©μ λΆλͺ¨ κ°μ²΄ μμ μ μμ κ°μ²΄λ μμ λΆλͺ¨κ° μμ΄μ§ μμ κ°μ²΄λ μλ μμ μλ μμ λΆλͺ¨κ° remove λ λ λΆλͺ¨ 컬λ μ μμ μμμ μ κ±°ν λ (κ΄κ³ λκΈΈ λ) μ¬μ© 쑰건 λΆλͺ¨-μμ μ°κ΄κ΄κ³ + cascade μ€μ λΆλͺ¨-μμ μ°κ΄κ΄κ³λ§ μμ΄λ κ°λ₯ (λ¨λ μ¬μ© κ°λ₯ β )