Skip to main content

πŸ“š kotlin Spring JAP μ–΄λ…Έν…Œμ΄μ…˜

μ–΄λ…Έν…Œμ΄μ…˜ μ™œ μ΄λ ‡κ²Œ μ“°λŠ” κ±°μ•Ό?​

package com.example.notesimple.domain

import jakarta.persistence.*
import java.time.LocalDateTime

@Entity
@Table(name = "notes")
class Note(
@Id @GeneratedValue(strategy = GenerationType.IDENTITY)
val id: Long? = null,

@Column(nullable = false, length = 200)
var title: String,

@Lob // λŒ€μš©λŸ‰
@Column(nullable = false)
var content: String? = null,
) : BaseEntity()

@MappedSuperclass
abstract class BaseEntity(
@Column(nullable = false, updatable = false)
val createdAt: LocalDateTime = LocalDateTime.now(),

@Column(nullable = false)
var updatedAt: LocalDateTime = LocalDateTime.now()
)
  1. μ–΄λ…Έν…Œμ΄μ…˜μ΄ λ₯ν˜€ μžˆλŠ”λ° μ΄λ ‡κ²Œ μ‚¬μš©ν•˜λŠ” μ΄μœ λŠ” 뭐야?
  2. μ–΄λ…Έν…Œμ΄μ…˜ ꡬ쑰가 λŒ€λž΅μ μœΌλ‘œ μ–΄λ–»κ²Œ λ˜μ–΄ μžˆλŠ”κ±°μ•Ό?
  3. import jakarta.persistence.* μ΄λ ‡κ²Œ λͺ¨λ“ κ±Έ λ‹€ μž„ν¬νŠΈ ν•˜λ©΄ λ©”λͺ¨λ¦¬ μ΅œμ ν™”λŠ” μ‹€νŒ¨ν•˜λŠ”κ±° 아냐?
  4. abstract class BaseEntity 둜 μ •μ˜ν•œλ‹€μŒ μƒμ†ν•˜λŠ” μ΄μœ λŠ”? κ·Έλƒ₯ 클래슀둜 λ§Œλ“€λ©΄ μ•ˆλ˜λŠ”κ±°μ•Ό?

  1. μ–΄λ…Έν…Œμ΄μ…˜μ΄ λ₯ν˜€ μžˆλŠ”λ° μ΄λ ‡κ²Œ μ‚¬μš©ν•˜λŠ” μ΄μœ λŠ” 뭐야?

    JPAμ—μ„œ μ–΄λ…Έν…Œμ΄μ…˜μ€ μ½”λ“œ μžμ²΄μ— 메타데이터λ₯Ό μΆ”κ°€ν•˜μ—¬, μ½”λ“œκ°€ νŠΉμ • λ°©μ‹μœΌλ‘œ λ™μž‘ν•˜λ„λ‘ ν”„λ ˆμž„μ›Œν¬λ‚˜ λΌμ΄λΈŒλŸ¬λ¦¬μ— μ§€μ‹œν•˜λŠ” 역할을 ν•©λ‹ˆλ‹€. XML μ„€μ • νŒŒμΌμ„ μ‚¬μš©ν•˜λŠ” 것보닀 κ°„κ²°ν•˜κ³ , μ½”λ“œμ™€ 섀정이 ν•¨κ»˜ μžˆμ–΄ 가독성과 μœ μ§€λ³΄μˆ˜μ„±μ΄ ν–₯μƒλ©λ‹ˆλ‹€.

    각 μ–΄λ…Έν…Œμ΄μ…˜μ˜ 역할을 μ‚΄νŽ΄λ³΄κ² μŠ΅λ‹ˆλ‹€:

    • @Entity: 이 ν΄λž˜μŠ€κ°€ λ°μ΄ν„°λ² μ΄μŠ€ ν…Œμ΄λΈ”κ³Ό λ§€ν•‘λ˜λŠ” JPA μ—”ν‹°ν‹°μž„μ„ λ‚˜νƒ€λƒ…λ‹ˆλ‹€. JPA 관리 ν•˜μ— μžˆλŠ” 객체가 λ©λ‹ˆλ‹€.
    • @Table(name = "notes"): μ—”ν‹°ν‹°κ°€ 맀핑될 λ°μ΄ν„°λ² μ΄μŠ€ ν…Œμ΄λΈ”μ˜ 이름을 notes둜 μ§€μ •ν•©λ‹ˆλ‹€. μ§€μ •ν•˜μ§€ μ•ŠμœΌλ©΄ 클래슀 이름(λŒ€μ†Œλ¬Έμž ꡬ뢄 방식은 κ΅¬ν˜„μ²΄μ— 따라 닀름)을 λ”°λ¦…λ‹ˆλ‹€.
    • @Id: 이 ν•„λ“œκ°€ μ—”ν‹°ν‹°μ˜ κΈ°λ³Έ ν‚€(Primary Key)μž„μ„ λ‚˜νƒ€λƒ…λ‹ˆλ‹€.
    • @GeneratedValue(strategy = GenerationType.IDENTITY): κΈ°λ³Έ ν‚€μ˜ 생성 μ „λž΅μ„ μ§€μ •ν•©λ‹ˆλ‹€. IDENTITYλŠ” λ°μ΄ν„°λ² μ΄μŠ€κ°€ κΈ°λ³Έ ν‚€ 생성을 λ‹΄λ‹Ήν•˜λ„λ‘ μœ„μž„ν•˜λŠ” λ°©μ‹μž…λ‹ˆλ‹€(예: MySQL의 AUTO_INCREMENT, PostgreSQL의 SERIAL).
    • @Column(nullable = false, length = 200): ν•„λ“œλ₯Ό λ°μ΄ν„°λ² μ΄μŠ€ μ»¬λŸΌμ— λ§€ν•‘ν•©λ‹ˆλ‹€.
      • nullable = false: 이 컬럼이 NOT NULL μ œμ•½ 쑰건을 갖도둝 ν•©λ‹ˆλ‹€.
      • length = 200: λ¬Έμžμ—΄ νƒ€μž… 컬럼의 μ΅œλŒ€ 길이λ₯Ό 200으둜 μ§€μ •ν•©λ‹ˆλ‹€.
    • @Lob: "Large Object"의 μ•½μžλ‘œ, λŒ€μš©λŸ‰ 데이터λ₯Ό μ €μž₯ν•˜λŠ” ν•„λ“œμ— μ‚¬μš©λ©λ‹ˆλ‹€. λ°μ΄ν„°λ² μ΄μŠ€μ—μ„œλŠ” CLOB (λ¬Έμžμ—΄) λ˜λŠ” BLOB (λ°”μ΄λ„ˆλ¦¬) νƒ€μž…μœΌλ‘œ λ§€ν•‘λ©λ‹ˆλ‹€. content ν•„λ“œκ°€ 맀우 κΈ΄ ν…μŠ€νŠΈλ₯Ό μ €μž₯ν•  수 μžˆμŒμ„ λ‚˜νƒ€λƒ…λ‹ˆλ‹€.
    • @MappedSuperclass: 이 μ–΄λ…Έν…Œμ΄μ…˜μ΄ 뢙은 ν΄λž˜μŠ€λŠ” μ—”ν‹°ν‹°κ°€ μ•„λ‹ˆλ©°, λ°μ΄ν„°λ² μ΄μŠ€ ν…Œμ΄λΈ”κ³Ό 직접 λ§€ν•‘λ˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€. λŒ€μ‹ , 이 클래슀λ₯Ό μƒμ†ν•˜λŠ” μ—”ν‹°ν‹° ν΄λž˜μŠ€λ“€μ΄ 이 ν΄λž˜μŠ€μ— μ •μ˜λœ ν•„λ“œμ™€ λ§€ν•‘ 정보λ₯Ό μƒμ†λ°›κ²Œ λ©λ‹ˆλ‹€. 곡톡 ν•„λ“œ(μ—¬κΈ°μ„œλŠ” createdAt, updatedAt)λ₯Ό μ—¬λŸ¬ μ—”ν‹°ν‹°μ—μ„œ μž¬μ‚¬μš©ν•˜κΈ° μœ„ν•΄ μ‚¬μš©λ©λ‹ˆλ‹€.
    • @Column(nullable = false, updatable = false) (BaseEntity의 createdAt):
      • updatable = false: μ—”ν‹°ν‹°κ°€ ν•œλ²ˆ μƒμ„±λœ ν›„μ—λŠ” 이 컬럼의 값이 λ°μ΄ν„°λ² μ΄μŠ€μ—μ„œ μ—…λ°μ΄νŠΈλ˜μ§€ μ•Šλ„λ‘ ν•©λ‹ˆλ‹€. 졜초 생성 μ‹œκ°μ„ κΈ°λ‘ν•˜λŠ” μš©λ„λ‘œ μ ν•©ν•©λ‹ˆλ‹€.

    결둠적으둜, μ–΄λ…Έν…Œμ΄μ…˜μ€ ORM (Object-Relational Mapping) ν”„λ ˆμž„μ›Œν¬μΈ JPAμ—κ²Œ ν΄λž˜μŠ€μ™€ ν•„λ“œλ₯Ό μ–΄λ–»κ²Œ λ°μ΄ν„°λ² μ΄μŠ€ μŠ€ν‚€λ§ˆμ— λ§€ν•‘ν•˜κ³  관리할지에 λŒ€ν•œ "μ§€μΉ¨"을 μ œκ³΅ν•˜λŠ” κ²ƒμž…λ‹ˆλ‹€.

  2. μ–΄λ…Έν…Œμ΄μ…˜ ꡬ쑰가 λŒ€λž΅μ μœΌλ‘œ μ–΄λ–»κ²Œ λ˜μ–΄ μžˆλŠ”κ±°μ•Ό?

    Java와 Kotlinμ—μ„œ μ–΄λ…Έν…Œμ΄μ…˜μ€ κ·Έ 자체둜 νŠΉλ³„ν•œ μ’…λ₯˜μ˜ μΈν„°νŽ˜μ΄μŠ€μž…λ‹ˆλ‹€. μ–΄λ…Έν…Œμ΄μ…˜μ„ μ •μ˜ν•  λ•ŒλŠ” @interface ν‚€μ›Œλ“œλ₯Ό μ‚¬μš©ν•©λ‹ˆλ‹€ (Java κΈ°μ€€, Kotlinμ—μ„œλŠ” Java μ–΄λ…Έν…Œμ΄μ…˜μ„ κ·ΈλŒ€λ‘œ μ‚¬μš©).

    μ–΄λ…Έν…Œμ΄μ…˜μ˜ ꡬ쑰λ₯Ό μ΄ν•΄ν•˜κΈ° μœ„ν•œ μ£Όμš” μš”μ†ŒλŠ” λ‹€μŒκ³Ό κ°™μŠ΅λ‹ˆλ‹€:

    • μ–΄λ…Έν…Œμ΄μ…˜ μ •μ˜ (Annotation Definition):

      // μ˜ˆμ‹œ: @Column μ–΄λ…Έν…Œμ΄μ…˜μ˜ κ°„λž΅ν™”λœ μ •μ˜ (μ‹€μ œ μ •μ˜λŠ” 더 λ³΅μž‘ν•¨)
      @Target({ElementType.METHOD, ElementType.FIELD}) // μ–΄λ…Έν…Œμ΄μ…˜μ„ μ μš©ν•  수 μžˆλŠ” λŒ€μƒ (λ©”μ†Œλ“œ, ν•„λ“œ λ“±)
      @Retention(RetentionPolicy.RUNTIME) // μ–΄λ…Έν…Œμ΄μ…˜ 정보λ₯Ό μ–Έμ œκΉŒμ§€ μœ μ§€ν•  것인가 (RUNTIME μ‹œμ κΉŒμ§€ μœ μ§€)
      public @interface Column {
      String name() default "";
      boolean unique() default false;
      boolean nullable() default true;
      int length() default 255;
      // ... 기타 속성듀
      }
    • 메타 μ–΄λ…Έν…Œμ΄μ…˜ (Meta-Annotations): μ–΄λ…Έν…Œμ΄μ…˜μ„ μ •μ˜ν•  λ•Œ μ‚¬μš©λ˜λŠ” μ–΄λ…Έν…Œμ΄μ…˜μž…λ‹ˆλ‹€.

      • @Target: ν•΄λ‹Ή μ–΄λ…Έν…Œμ΄μ…˜μ΄ 어디에 μ‚¬μš©λ  수 μžˆλŠ”μ§€λ₯Ό μ§€μ •ν•©λ‹ˆλ‹€. (예: ElementType.TYPE은 클래슀/μΈν„°νŽ˜μ΄μŠ€, ElementType.FIELDλŠ” ν•„λ“œ, ElementType.METHODλŠ” λ©”μ†Œλ“œ)
      • @Retention: μ–΄λ…Έν…Œμ΄μ…˜ 정보가 μ–Έμ œκΉŒμ§€ μœ μ§€λ μ§€λ₯Ό μ§€μ •ν•©λ‹ˆλ‹€.
        • RetentionPolicy.SOURCE: μ†ŒμŠ€ μ½”λ“œμ—λ§Œ μ‘΄μž¬ν•˜λ©°, 컴파일 μ‹œ μ‚¬λΌμ§‘λ‹ˆλ‹€.
        • RetentionPolicy.CLASS: 컴파일된 클래슀 νŒŒμΌμ—λŠ” μ‘΄μž¬ν•˜μ§€λ§Œ, λŸ°νƒ€μž„ μ‹œ JVMμ—μ„œλŠ” λ‘œλ“œλ˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€. (κΈ°λ³Έκ°’)
        • RetentionPolicy.RUNTIME: 컴파일된 클래슀 νŒŒμΌμ—λ„ μ‘΄μž¬ν•˜λ©°, λŸ°νƒ€μž„ μ‹œ JVM에 μ˜ν•΄ λ‘œλ“œλ˜μ–΄ λ¦¬ν”Œλ ‰μ…˜μ„ 톡해 μ‘°νšŒν•  수 μžˆμŠ΅λ‹ˆλ‹€. JPA μ–΄λ…Έν…Œμ΄μ…˜λ“€μ€ λŒ€λΆ€λΆ„ RUNTIME으둜 μ§€μ •λ˜μ–΄ JPA κ΅¬ν˜„μ²΄κ°€ λŸ°νƒ€μž„μ— 이 정보λ₯Ό 읽어 ORM μž‘μ—…μ„ μˆ˜ν–‰ν•©λ‹ˆλ‹€.
      • @Documented: JavaDoc 생성 μ‹œ μ–΄λ…Έν…Œμ΄μ…˜ 정보도 ν¬ν•¨ν•˜λ„λ‘ ν•©λ‹ˆλ‹€.
      • @Inherited: λΆ€λͺ¨ 클래슀의 μ–΄λ…Έν…Œμ΄μ…˜μ΄ μžμ‹ ν΄λž˜μŠ€μ—κ²Œλ„ μƒμ†λ˜λ„λ‘ ν•©λ‹ˆλ‹€. (@MappedSuperclassμ™€λŠ” λ‹€λ₯Έ κ°œλ…μœΌλ‘œ, 주둜 클래슀 레벨 μ–΄λ…Έν…Œμ΄μ…˜μ— 적용)
    • μ–΄λ…Έν…Œμ΄μ…˜ μš”μ†Œ (Annotation Elements/Attributes): μ–΄λ…Έν…Œμ΄μ…˜ 내에 μ„ μ–Έλœ λ©”μ†Œλ“œλ“€μž…λ‹ˆλ‹€. 이 λ©”μ†Œλ“œλ“€μ€ μ–΄λ…Έν…Œμ΄μ…˜ μ‚¬μš©μžμ—κ²Œ νŒŒλΌλ―Έν„°μ²˜λŸΌ 값을 전달받을 수 있게 ν•΄μ€λ‹ˆλ‹€. 예λ₯Ό λ“€μ–΄ @Column(nullable = false)μ—μ„œ nullable이 μš”μ†Œμ΄κ³  falseκ°€ κ·Έ κ°’μž…λ‹ˆλ‹€. default ν‚€μ›Œλ“œλ₯Ό μ‚¬μš©ν•˜μ—¬ 기본값을 μ§€μ •ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

    JPA μ–΄λ…Έν…Œμ΄μ…˜λ“€μ€ jakarta.persistence νŒ¨ν‚€μ§€μ— μ •μ˜λ˜μ–΄ 있으며, λŒ€λΆ€λΆ„ @Retention(RetentionPolicy.RUNTIME)으둜 μ„€μ •λ˜μ–΄ JPA ν”„λ‘œλ°”μ΄λ”(예: Hibernate)κ°€ λŸ°νƒ€μž„μ— 이 메타데이터λ₯Ό 읽어 λ™μ μœΌλ‘œ SQL을 μƒμ„±ν•˜κ³  객체-ν…Œμ΄λΈ” 맀핑을 μ²˜λ¦¬ν•©λ‹ˆλ‹€.

  3. import jakarta.persistence.* μ΄λ ‡κ²Œ λͺ¨λ“ κ±Έ λ‹€ μž„ν¬νŠΈ ν•˜λ©΄ λ©”λͺ¨λ¦¬ μ΅œμ ν™”λŠ” μ‹€νŒ¨ν•˜λŠ”κ±° 아냐?

    κ²°λ‘ λΆ€ν„° λ§μ”€λ“œλ¦¬λ©΄, import jakarta.persistence.*와 같이 μ™€μΌλ“œμΉ΄λ“œ(*) μž„ν¬νŠΈλ₯Ό μ‚¬μš©ν•œλ‹€κ³  ν•΄μ„œ λŸ°νƒ€μž„ λ©”λͺ¨λ¦¬ μ΅œμ ν™”κ°€ μ§μ ‘μ μœΌλ‘œ μ‹€νŒ¨ν•˜κ±°λ‚˜ λΆˆν•„μš”ν•œ ν΄λž˜μŠ€λ“€μ΄ λ©”λͺ¨λ¦¬μ— λ‘œλ“œλ˜λŠ” 것은 μ•„λ‹™λ‹ˆλ‹€.

    μ΄μœ λŠ” λ‹€μŒκ³Ό κ°™μŠ΅λ‹ˆλ‹€:

    • 컴파일 νƒ€μž„ 처리: import 문은 μ»΄νŒŒμΌλŸ¬μ—κ²Œ 클래슀 이름을 찾을 경둜λ₯Ό μ•Œλ €μ£ΌλŠ” μ§€μ‹œμ–΄μž…λ‹ˆλ‹€. μ™€μΌλ“œμΉ΄λ“œ μž„ν¬νŠΈλŠ” μ»΄νŒŒμΌλŸ¬κ°€ ν•΄λ‹Ή νŒ¨ν‚€μ§€ λ‚΄μ—μ„œ ν•„μš”ν•œ 클래슀λ₯Ό 찾을 수 μžˆλ„λ‘ ν•˜λŠ” νŽΈλ¦¬ν•œ 방법일 λΏμž…λ‹ˆλ‹€.
    • λ°”μ΄νŠΈμ½”λ“œ: 컴파일이 μ™„λ£Œλ˜λ©΄, μƒμ„±λœ λ°”μ΄νŠΈμ½”λ“œμ—λŠ” μ‹€μ œλ‘œ μ½”λ“œ λ‚΄μ—μ„œ μ‚¬μš©λœ ν΄λž˜μŠ€λ“€μ— λŒ€ν•œ 참쑰만 ν¬ν•¨λ©λ‹ˆλ‹€. jakarta.persistence.*라고 μž„ν¬νŠΈν–ˆλ”λΌλ„, μ½”λ“œμ—μ„œ @Entity, @Id 두 개만 μ‚¬μš©ν–ˆλ‹€λ©΄ λ°”μ΄νŠΈμ½”λ“œμ—λŠ” 이 두 ν΄λž˜μŠ€μ— λŒ€ν•œ 참쑰만 λ“€μ–΄κ°‘λ‹ˆλ‹€. νŒ¨ν‚€μ§€ λ‚΄μ˜ μ‚¬μš©λ˜μ§€ μ•Šμ€ λ‹€λ₯Έ λͺ¨λ“  ν΄λž˜μŠ€λ“€μ€ λ°”μ΄νŠΈμ½”λ“œμ— ν¬ν•¨λ˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€.
    • 클래슀 λ‘œλ”©: JVM은 ν΄λž˜μŠ€κ°€ μ‹€μ œλ‘œ ν•„μš”ν•  λ•Œ (예: ν•΄λ‹Ή 클래슀의 객체λ₯Ό μƒμ„±ν•˜κ±°λ‚˜ 정적 멀버에 μ ‘κ·Όν•  λ•Œ) 클래슀 λ‘œλ”λ₯Ό 톡해 λ©”λͺ¨λ¦¬μ— λ‘œλ“œν•©λ‹ˆλ‹€. μ™€μΌλ“œμΉ΄λ“œ μž„ν¬νŠΈ μžμ²΄κ°€ μ‚¬μš©ν•˜μ§€ μ•ŠλŠ” ν΄λž˜μŠ€λ“€κΉŒμ§€ 미리 λ‘œλ“œν•˜μ§€λŠ” μ•ŠμŠ΅λ‹ˆλ‹€.

    ν•˜μ§€λ§Œ μ™€μΌλ“œμΉ΄λ“œ μž„ν¬νŠΈμ—λŠ” λ‹€λ₯Έ 고렀사항이 μžˆμŠ΅λ‹ˆλ‹€:

    • 가독성 및 λͺ…ν™•μ„±: μ–΄λ–€ ν΄λž˜μŠ€λ“€μ΄ μ‚¬μš©λ˜λŠ”μ§€ μž„ν¬νŠΈ λͺ©λ‘λ§Œ 보고 λͺ…ν™•νžˆ μ•ŒκΈ° μ–΄λ €μ›Œμ§ˆ 수 μžˆμŠ΅λ‹ˆλ‹€. λ‹€λ₯Έ νŒ¨ν‚€μ§€μ— λ™μΌν•œ μ΄λ¦„μ˜ ν΄λž˜μŠ€κ°€ μžˆμ„ 경우 이름 좩돌의 κ°€λŠ₯성도 (μ΄λ‘ μ μœΌλ‘œλŠ”) μ‘΄μž¬ν•©λ‹ˆλ‹€.
    • λΉŒλ“œ μ‹œκ°„: μ•„μ£Ό λ§Žμ€ ν΄λž˜μŠ€κ°€ μžˆλŠ” νŒ¨ν‚€μ§€λ₯Ό μ™€μΌλ“œμΉ΄λ“œλ‘œ μž„ν¬νŠΈν•˜κ³  그쀑 μ†Œμˆ˜λ§Œ μ‚¬μš©ν•œλ‹€λ©΄, μ»΄νŒŒμΌλŸ¬κ°€ 심볼을 μ°ΎλŠ” 데 μ•½κ°„μ˜ μΆ”κ°€ μ‹œκ°„μ΄ μ†Œμš”λ  수 μžˆμ§€λ§Œ, ν˜„λŒ€μ μΈ μ»΄νŒŒμΌλŸ¬μ—μ„œλŠ” 이 영ν–₯이 λ―Έλ―Έν•©λ‹ˆλ‹€.
    • IDE 지원: ν˜„λŒ€ IDE듀은 μ‚¬μš©ν•˜μ§€ μ•ŠλŠ” μž„ν¬νŠΈλ₯Ό μ •λ¦¬ν•΄μ£Όκ±°λ‚˜, λͺ…μ‹œμ  μž„ν¬νŠΈλ₯Ό μžλ™μœΌλ‘œ μΆ”κ°€/κ΄€λ¦¬ν•΄μ£ΌλŠ” κΈ°λŠ₯이 잘 λ˜μ–΄ μžˆμ–΄ 개발 νŽΈμ˜μ„±κ³Ό λͺ…ν™•μ„± μ‚¬μ΄μ—μ„œ κ· ν˜•μ„ μž‘μ„ 수 μžˆμŠ΅λ‹ˆλ‹€.

    λ”°λΌμ„œ λ©”λͺ¨λ¦¬ μ΅œμ ν™” κ΄€μ μ—μ„œ μ™€μΌλ“œμΉ΄λ“œ μž„ν¬νŠΈλŠ” 큰 λ¬Έμ œκ°€ λ˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€. 주둜 μ½”λ“œμ˜ λͺ…ν™•μ„±κ³Ό νŒ€/νšŒμ‚¬μ˜ μ½”λ”© μ»¨λ²€μ…˜μ— 따라 μ‚¬μš© μ—¬λΆ€λ₯Ό κ²°μ •ν•©λ‹ˆλ‹€. Spring Bootλ‚˜ λ§Žμ€ λΌμ΄λΈŒλŸ¬λ¦¬μ—μ„œ κ΄€λ‘€μ μœΌλ‘œ JPA μ–΄λ…Έν…Œμ΄μ…˜μ„ μ‚¬μš©ν•  λ•Œ jakarta.persistence.* 와 같이 μ™€μΌλ“œμΉ΄λ“œλ‘œ μž„ν¬νŠΈν•˜λŠ” κ²½μš°κ°€ ν”ν•©λ‹ˆλ‹€.

  4. abstract class BaseEntity 둜 μ •μ˜ν•œλ‹€μŒ μƒμ†ν•˜λŠ” μ΄μœ λŠ”? κ·Έλƒ₯ 클래슀둜 λ§Œλ“€λ©΄ μ•ˆλ˜λŠ”κ±°μ•Ό?

    BaseEntityλ₯Ό abstract class둜 μ •μ˜ν•˜κ³  @MappedSuperclass μ–΄λ…Έν…Œμ΄μ…˜μ„ λΆ™μ—¬ μ‚¬μš©ν•˜λŠ” 주된 μ΄μœ λŠ” λ‹€μŒκ³Ό κ°™μŠ΅λ‹ˆλ‹€:

    • 곡톡 ν•„λ“œ μž¬μ‚¬μš© 및 쀑볡 제거: μ—¬λŸ¬ μ—”ν‹°ν‹° ν΄λž˜μŠ€μ—μ„œ κ³΅ν†΅μ μœΌλ‘œ μ‚¬μš©λ˜λŠ” ν•„λ“œλ“€(예: createdAt, updatedAt 같은 생성/μˆ˜μ • μ‹œκ° 정보, createdBy, updatedBy 같은 생성/μˆ˜μ •μž 정보)을 ν•œ κ³³μ—μ„œ μ •μ˜ν•˜κ³ , 이λ₯Ό μƒμ†λ°›λŠ” λͺ¨λ“  μ—”ν‹°ν‹°κ°€ ν•΄λ‹Ή ν•„λ“œμ™€ λ§€ν•‘ 정보λ₯Ό μžλ™μœΌλ‘œ 갖도둝 ν•˜κΈ° μœ„ν•¨μž…λ‹ˆλ‹€. 이λ₯Ό 톡해 μ½”λ“œ 쀑볡을 쀄이고 일관성을 μœ μ§€ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

    • @MappedSuperclass의 νŠΉμ„±:

      • @MappedSuperclass둜 μ§€μ •λœ ν΄λž˜μŠ€λŠ” κ·Έ 자체둜 μ—”ν‹°ν‹°κ°€ μ•„λ‹™λ‹ˆλ‹€. 즉, λ°μ΄ν„°λ² μ΄μŠ€μ— BaseEntityλΌλŠ” μ΄λ¦„μ˜ ν…Œμ΄λΈ”μ΄ μƒμ„±λ˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€.
      • 이 ν΄λž˜μŠ€μ— μ •μ˜λœ ν•„λ“œλ“€μ€ 이 클래슀λ₯Ό μƒμ†ν•˜λŠ” μžμ‹ μ—”ν‹°ν‹°λ“€μ˜ ν…Œμ΄λΈ”μ— 컬럼으둜 ν¬ν•¨λ©λ‹ˆλ‹€.
      • JPA의 일반적인 μ—”ν‹°ν‹° 상속(@Inheritance μ–΄λ…Έν…Œμ΄μ…˜ μ‚¬μš©)κ³ΌλŠ” λ‹€λ¦…λ‹ˆλ‹€. μ—”ν‹°ν‹° 상속은 λΆ€λͺ¨ ν΄λž˜μŠ€λ„ μ—”ν‹°ν‹°μ΄κ±°λ‚˜, νŠΉμ • μ „λž΅(단일 ν…Œμ΄λΈ”, 쑰인 ν…Œμ΄λΈ” λ“±)에 따라 ν…Œμ΄λΈ” ꡬ쑰가 κ²°μ •λ©λ‹ˆλ‹€. @MappedSuperclassλŠ” λ‹¨μˆœνžˆ λ§€ν•‘ μ •λ³΄λ§Œ μƒμ†ν•©λ‹ˆλ‹€.
    • abstract ν‚€μ›Œλ“œλ₯Ό μ‚¬μš©ν•˜λŠ” 이유:

      1. λͺ…ν™•ν•œ μ˜λ„: BaseEntityλŠ” λ…λ¦½μ μœΌλ‘œ μΈμŠ€ν„΄μŠ€ν™”λ˜μ–΄ μ‚¬μš©λ  λͺ©μ μ΄ μ•„λ‹ˆλΌ, 였직 λ‹€λ₯Έ μ—”ν‹°ν‹°λ“€μ—κ²Œ 곡톡 속성을 μ œκ³΅ν•˜κΈ° μœ„ν•œ "ν…œν”Œλ¦Ώ"μ΄λ‚˜ "뢀뢄적인 μ •μ˜"의 역할을 ν•©λ‹ˆλ‹€. abstract ν‚€μ›Œλ“œλŠ” μ΄λŸ¬ν•œ μ˜λ„λ₯Ό λͺ…ν™•νžˆ λ‚˜νƒ€λƒ…λ‹ˆλ‹€. "이 ν΄λž˜μŠ€λŠ” 직접 객체둜 λ§Œλ“€ 수 μ—†κ³ , λ°˜λ“œμ‹œ μƒμ†ν•΄μ„œ μ‚¬μš©ν•΄μ•Ό ν•œλ‹€"λŠ” 의미λ₯Ό λΆ€μ—¬ν•©λ‹ˆλ‹€.
      2. 객체 생성 λ°©μ§€: abstract ν΄λž˜μŠ€λŠ” 직접 new BaseEntity()와 같이 μΈμŠ€ν„΄μŠ€ν™”ν•  수 μ—†μŠ΅λ‹ˆλ‹€. @MappedSuperclass의 λͺ©μ μƒ BaseEntity 객체λ₯Ό 직접 μƒμ„±ν•˜μ—¬ JPA μ»¨ν…μŠ€νŠΈμ—μ„œ 관리할 ν•„μš”κ°€ μ—†μœΌλ―€λ‘œ, abstract둜 λ§Œλ“€μ–΄ μ‹€μˆ˜λ‘œλΌλ„ 직접 μΈμŠ€ν„΄μŠ€ν™”ν•˜λŠ” 것을 λ§‰λŠ” 것이 μ’‹μŠ΅λ‹ˆλ‹€.

    κ·Έλƒ₯ 클래슀둜 λ§Œλ“€λ©΄ μ•ˆλ˜λŠ”κ±°μ•Ό? (non-abstract class)

    λ„€, 기술적으둜 BaseEntityλ₯Ό abstractκ°€ μ•„λ‹Œ 일반 클래슀둜 λ§Œλ“€κ³  @MappedSuperclassλ₯Ό 뢙여도 JPAλŠ” λ™μΌν•˜κ²Œ λ™μž‘ν•©λ‹ˆλ‹€. 즉, μžμ‹ 엔티티듀은 BaseEntity의 ν•„λ“œλ“€μ„ 상속받아 μžμ‹ μ˜ ν…Œμ΄λΈ”μ— 컬럼으둜 κ°–κ²Œ λ©λ‹ˆλ‹€.

    ν•˜μ§€λ§Œ μ΄λ ‡κ²Œ ν•  경우:

    • BaseEntityκ°€ 일반 ν΄λž˜μŠ€μ΄λ―€λ‘œ new BaseEntity()둜 객체 생성이 κ°€λŠ₯ν•΄μ§‘λ‹ˆλ‹€. κ·ΈλŸ¬λ‚˜ 이 κ°μ²΄λŠ” JPA μ—”ν‹°ν‹°κ°€ μ•„λ‹ˆλ―€λ‘œ μ˜μ†μ„± μ»¨ν…μŠ€νŠΈμ— μ˜ν•΄ κ΄€λ¦¬λ˜κ±°λ‚˜ λ°μ΄ν„°λ² μ΄μŠ€μ— μ €μž₯될 수 μ—†μŠ΅λ‹ˆλ‹€. μ΄λŸ¬ν•œ 객체 생성이 μ˜λ―Έκ°€ μ—†κ³  ν˜Όλž€μ„ μ•ΌκΈ°ν•  수 μžˆμŠ΅λ‹ˆλ‹€.
    • 클래슀 μ„€κ³„μ˜ μ˜λ„κ°€ λΆˆλΆ„λͺ…ν•΄μ§ˆ 수 μžˆμŠ΅λ‹ˆλ‹€. abstractλ₯Ό μ‚¬μš©ν•˜λ©΄ "이것은 λΆˆμ™„μ „ν•œ μ •μ˜μ΄λ©°, 상속을 톡해 μ™„μ„±λ˜μ–΄μ•Ό ν•œλ‹€"λŠ” λ©”μ‹œμ§€κ°€ λͺ…ν™•ν•΄μ§‘λ‹ˆλ‹€.

    λ”°λΌμ„œ @MappedSuperclassλ₯Ό μ‚¬μš©ν•˜λŠ” ν΄λž˜μŠ€λŠ” κ°œλ…μ μœΌλ‘œλ‚˜ μ„€κ³„μ μœΌλ‘œ abstract둜 μ„ μ–Έν•˜λŠ” 것이 더 μ˜¬λ°”λ₯΄κ³  일반적인 κ΄€λ‘€μž…λ‹ˆλ‹€. μ΄λŠ” ν•΄λ‹Ή ν΄λž˜μŠ€κ°€ 독립적인 μ—”ν‹°ν‹°κ°€ μ•„λ‹ˆλΌ 곡톡 λ§€ν•‘ 정보λ₯Ό μ œκ³΅ν•˜κΈ° μœ„ν•œ μƒμœ„ ν΄λž˜μŠ€μž„μ„ λͺ…ν™•νžˆ ν•˜κΈ° μœ„ν•¨μž…λ‹ˆλ‹€.