@MappedSuperclass and @EnableJpaAuditing

GEONNY·2024년 8월 1일
0

Building-API

목록 보기
13/28
post-thumbnail

📌@MappedSuperclass

대부분 프로젝트의 Database Table 에는 등록일시, 수정일시와 같이 중복되는 컬럼들이 있습니다. JPA 에서는 @MappedSuperclass 를 사용하여 중복되는 컬럼들을 추상화 클래스의 필드로 추가하고 이를 상속받아 사용할 수 있습니다.

이전에 생성했던 Member 와 Authority Entity 에도 createDate 와 updateDate 가 있었습니다. 이 필드들을 BaseEntity를 생성하여 이동하고 Member, Authority entity에서 이를 상속받도록 수정해 주겠습니다.
entity.base.BaseEntity

@MappedSuperclass
@Getter
public abstract class BaseEntity {
    @Column(name = "update_dt")
    @Temporal(TemporalType.TIMESTAMP)
    private LocalDateTime updateDate;

    @Column(name = "create_dt", updatable = false)
    @Temporal(TemporalType.TIMESTAMP)
    private LocalDateTime createDate;
}

BaseEntity 는 실제 Entity 가 아니고 공통 필드의 묶음이기 때문에 new BaseEntity(); 와 같이 인스턴스 생성을 막기 위해 추상 클래스로 생성합니다.
entity.Member

@Getter
@Builder
@NoArgsConstructor
@AllArgsConstructor
@Table
@Entity(name = "member")
public class Member extends BaseEntity {

    @Id
    @Column(name = "member_id")
    private String memberId;

    @Column(name = "member_pw")
    private String password;

    @Column(name = "member_nm")
    private String memberName;

    @Column(name = "use_yn")
    private String useYn;

    @Column(name = "authority_cd")
    private String authorityCode;
}

entity.Authority

@Getter
@Builder
@NoArgsConstructor
@AllArgsConstructor
@Table
@Entity(name = "authority")
public class Authority extends BaseEntity {

    @Id
    @Column(name = "authority_cd")
    private String authorityCode;

    @Column(name = "authority_nm")
    private String authorityName;
}

📌@EnableJpaAuditing

Auditing 은 감사 : 감독하고 검사함. 라는 의미로 JPA 에서는 데이터의 변경이력 감사하는 의미로 이해하시면 됩니다.

@EnableJpaAuditing 은 Springboot main class 에 추가하여 기능을 활성화 해야 합니다.

@SpringBootApplication
@EnableJpaAuditing
public class ApiApplication {

	public static void main(String[] args) {
		SpringApplication.run(ApiApplication.class, args);
	}
}

📍Auditing 필드 종류

Auditing 이 가능한 필드의 종류에는 4가지가 있습니다.
@CreatedBy Entity 영속 시 생성한 사용자 정보 저장
@CreatedDate Entity 영속 시 생성일시 저장
@LastModifiedBy 영속 상태의 Entity 수정 시 수정한 사용자 정보 저장
@LastModifiedDate 영속 상태의 Entity 수정 시 수정일시 저장

📍Auditing 적용 방법

Auditing 할 필드가 있는 Entity 에 @EntityListeners(AuditingEntityListener.class) 를 추가해 주고 적용할 필드에 위 4 가지 Annotaion 을 기능에 맞게 추가합니다.
BaseEntity 에 적용해 보도록 하죠.
entity.base.BaseEntity

@MappedSuperclass
@Getter
@EntityListeners(AuditingEntityListener.class)
public abstract class BaseEntity {
    @Column(name = "update_dt")
    @Temporal(TemporalType.TIMESTAMP)
    @LastModifiedDate
    private LocalDateTime updateDate;

    @Column(name = "create_dt", updatable = false)
    @Temporal(TemporalType.TIMESTAMP)
    @CreatedDate
    private LocalDateTime createDate;
}

다음에는 Member CUD Operation 을 구현하면서 Auditing 이 정상적으로 동작하는지 확인해 보도록 하겠습니다.😄

📚참고

📕JPA 생명주기

JPA Entity 의 생명주기에는 4가지가 있습니다.
비영속 : JPA 와 관계 없이 Entity만 생성한 상태를 의미

// 단순히 Entity 만 생성 (비영속)
Member member = new Member("meber1", "1234", "회원1");

영속 : JPA에 의해서 관리되는 상태를 의미

//영속 상태의 객체를 조회 (영속)
Member member = memberRepository.findById(String memberId);

//새로 생성한 객체를 영속 상태로 변경
Member member = new Member("meber1", "1234", "회원1");
memberRepository.save(member); // EntityManager.persist(member); 가 호출되면서 영속 상태가 됨.

참고) save method

@Override
@Transactional
public <S extends T> S save(S entity) {

	Assert.notNull(entity, "Entity must not be null");

	if (entityInformation.isNew(entity)) {
		entityManager.persist(entity); //영속 상태로 만듬.
		return entity;
	} else {
		return entityManager.merge(entity);
	}
}

준영속 : 영속 상태의 Entity를 해제 (detach)

Optional<Member> member = memberRepository.findById(memberId); //영속
entityManager.detach(member.get()); // 준영속 상태

삭제 : 1차 캐시와 Database 에서 모두 삭제된 상태를 의미

Optional<Member> member = memberRepository.findById(memberId); //영속
memberRepository.delete(member.get()); // 삭제

참고) delete method

@Override
@Transactional
@SuppressWarnings("unchecked")
public void delete(T entity) {

	Assert.notNull(entity, "Entity must not be null");

	if (entityInformation.isNew(entity)) {
		return;
	}

	Class<?> type = ProxyUtils.getUserClass(entity);

	T existing = (T) entityManager.find(type, entityInformation.getId(entity));

	// if the entity to be deleted doesn't exist, delete is a NOOP
	if (existing == null) {
		return;
	}

	entityManager.remove(entityManager.contains(entity)  // 삭제
       	? entity 
        : entityManager.merge(entity));
}
profile
Back-end developer

0개의 댓글