Lined Notebook

[Spring Data JPA] 19. JPA MappedSuperclass 사용

by ymkim

✔ @MappedSuperclass

mapped_superclass

MappedSuperclass는 공통매핑 정보가 필요한 경우 사용이 된다. 대표적인 예로는 DB 테이블이 다르지만 부모 클래스의 속성만 하위 구현체에서 물려받아 사용하고 싶은 경우 사용이 된다.

✅ 공통 엔티티가 없다 가정

@Entity
public class Member {
    private String createdBy;
    private LocalDateTime createdDate;
    private String lastModifiedBy;
    private LocalDateTime lastModifiedDate;
}
@Entity
public class Item {
    private String createdBy;
    private LocalDateTime createdDate;
    private String lastModifiedBy;
    private LocalDateTime lastModifiedDate;
}

다른 엔티티는 중략 하였습니다.

만약 DBA가 생성자, 생성일, 정의자, 정의일에 대한 컬럼을 추가해달라는 요구사항이 있다 가정하자. 만약 공통적으로 해결 할 수 있는 부분이 존재하지 않는다면 각각의 모든 클래스에 해당 4개의 컬럼을 추가해줘야 할 것이다.

✅ 공통 엔티티 생성

@MappedSuperclass // 매핑 정보에 대한 부분만 받는 엔티티
public abstract class BaseEntity {

    /*
    컬럼명을 지정하여 사용하는 것도 가능하다.
    @Column(name = "INSERT_MEMBER")
    private String createdBy;
    */

    private String createdBy;
    private LocalDateTime createdDate;
    private String lastModifiedBy;
    private LocalDateTime lastModifiedDate;

    //.. Getter, Setter 중략
}

위처럼 @MappedSuperclass 어노테이션을 선언하면 해당 엔티티를 상속 받는 하위 구현체들에게 공통적인 매핑 정보를 제공 할 수 있다.

✅ 상속 관계 설정

// @Entity
public class Member extends BaseEntity { }
public class Item extends BaseEntity { }

Member, Item 엔티티는 BaseEntity를 상속한다.

✅ 호출부

public class JpaMain {

    public static void main(String[] args) {
        EntityManagerFactory emf = Persistence.createEntityManagerFactory("hello");
        EntityManager em = emf.createEntityManager();

        EntityTransaction tx = em.getTransaction();
        tx.begin();

        try {
            Member member = new Member();
            member.setUsername("user1");
            member.setCreatedBy("ymkim");
            member.setCreatedDate(LocalDateTime.now());

            em.persist(member);
            em.flush();
            em.clear();

            tx.commit();
        } catch (Exception e) {
            tx.rollback();
        } finally {
            em.close();
        }

        emf.close();
    }
}

현재 Member 엔티티는 BaseEntity를 상속하여 생성일, 생성자를 셋팅하고 있습니다. 출력 결과를 한번 살펴보겠습니다.

🖨️ 출력 결과

Hibernate:

    create table Item (
       DTYPE varchar(31) not null,
        id bigint not null,
        createdBy varchar(255),
        createdDate timestamp,
        lastModifiedBy varchar(255),
        lastModifiedDate timestamp,
        name varchar(255),
        price integer not null,
        primary key (id)
    )

Hibernate:

    create table Member (
       MEMBER_ID bigint not null,
        createdBy varchar(255),
        createdDate timestamp,
        lastModifiedBy varchar(255),
        lastModifiedDate timestamp,
        USERNAME varchar(255),
        LOCKER_ID bigint,
        TEAM_ID bigint,
        primary key (MEMBER_ID)
    )
  • 공통 정보 필드가 생성됨.

🔥 @MappedSuperclass 특징-1

  • 상속관계 매핑, 엔티티가 아니다.
  • 테이블과의 매핑은 불가능하다.
  • 부모 클래스를 상속 받는 자식 클래스에 매핑 정보만 제공
  • 조회, 검색 불가 (em.find(BaseEntity))
  • 직접 생성해서 사용할 일이 없으므로 추상 클래스 권장.
// 조회 불가능 예시
em.find(BaseEntity.class, 중략)

🔥 @MappedSuperclass 특징-2

  • 테이블과 관계가 없고 단순히 엔티티가 공통으로 사용하는 매핑정보를 모은다.
  • 주로 등록일, 수정일, 등록자 등의 공통 정보를 모을 때 사용.
  • @Entity 클래스는 @Entity나 @MappedSuperclass로 지정한 클래스만 상속 가능.

⚡ 결론

@MappedSupperclass를 사용하는 이유는 자바에서의 상속과 마찬가지로, 공통적인 특징(속성)을 하위 클래스에서 물려받아 사용하는 경우 사용한다 생각하자.

참고 자료

블로그의 정보

기록하고, 복기하고

ymkim

활동하기