티스토리 뷰

 

 

등록 수정에 대한 내용이 없으면 유지보수 등 나중에 확인할 때에 문제가 생길 수도 있다. 김영한개발자님은 모든 테이블에 등록, 수정 내용을 꼭 남긴다고 한다.

 

같은 데이터의 모양이므로 하나의 클래스로 진행한다. 실무에서도 자주 쓰는 기술이라 한다.

 

순수 JPA

package study.datajpa.entity;

import jakarta.persistence.Column;
import jakarta.persistence.MappedSuperclass;
import jakarta.persistence.PrePersist;
import jakarta.persistence.PreUpdate;

import java.time.LocalDateTime;

@MappedSuperclass
public class JpaBaseEntity {

    @Column(updatable = false) //생성일은 수정할 일이 없기 때문에 막아준다.
    private LocalDateTime createDate;
    private LocalDateTime updateDate;

    @PrePersist
    public void prePersist(){
        LocalDateTime now = LocalDateTime.now();
        createDate = now;
        updateDate = now; //업데이트에도 넣는 이유는 updateDate가 비어져 있으면 후에 쿼리를 날릴 때에 null값으로 인해 지저분해진다.
    }

    @PreUpdate
    public void preUpdate(){
        updateDate = LocalDateTime.now();
    }
}

 

클래스 위의 어노테이션 @MappedSuperClass를 붙여줘야 테이블에서도 진짜 사용하는 것이 된다.

 

package study.datajpa.entity;

import jakarta.persistence.*;
import lombok.*;

@Entity
@Getter @Setter
@NoArgsConstructor(access = AccessLevel.PROTECTED) // 기본생성자 만들기, 기본생성자는 JPA 스펙으로 private는 안된다.
@ToString(of = {"id", "username", "age"}) //toString을 만들 때에는 가급적이면 연관관계객체는 넣지 않는것이 좋다(서로 부르면서 무한루프 된다.)
@NamedQuery(
        name="Member.findByUsername",
        query="select m from Member m where m.username =: username"
)
@NamedEntityGraph(name = "Member.All" , attributeNodes = @NamedAttributeNode("team"))
public class Member extends JpaBaseEntity{

    @Id @GeneratedValue
    @Column(name = "member_id")
    private Long id;
    private String username;
    private int age;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "team_id")
    private Team team;

    public Member(String username) { this.username = username; }

    public Member(String username, int age) {
        this.username = username;
        this.age = age;
    }
    public Member(String username, int age, Team team) {
        this.username = username;
        this.age = age;

        if(team != null) {
            changeTeam(team);
        }
    }

    public void changeTeam(Team team){
        this.team = team;
        team.getMembers().add(this);
    }
}

 

엔티티에 상속해서 사용한다.

 

    @Test
    public void jpaEventBaseEntity() throws Exception {
        Member member = new Member("member1" , 109);
        memberRepository.save(member); //@PrePersist 발생

        Thread.sleep(100);

        member.setUsername("member22"); //변경 감지

        em.flush();// @PreUpdate
        em.clear();

    }

 

 

이렇게 잘 사용하면 간편하게 모든 테이블에 extends해서 사용하면 편하다.

 

DataJpa

@EnableJpaAuditing
@SpringBootApplication
public class DataJpaApplication {

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

}

- 스프링부트 설정 클래스에 @EnableJpaAuditing을 넣어준다.

 

 

package study.datajpa.entity;

import jakarta.persistence.Column;
import jakarta.persistence.EntityListeners;
import jakarta.persistence.MappedSuperclass;
import lombok.Getter;
import org.springframework.context.event.EventListener;
import org.springframework.data.annotation.CreatedBy;
import org.springframework.data.annotation.CreatedDate;
import org.springframework.data.annotation.LastModifiedBy;
import org.springframework.data.annotation.LastModifiedDate;
import org.springframework.data.jpa.domain.support.AuditingEntityListener;

import java.time.LocalDateTime;

@EntityListeners(AuditingEntityListener.class)
@Getter
@MappedSuperclass
public class BaseEntity {

    @CreatedDate
    @Column(updatable = false)
    private LocalDateTime createDate;

    @LastModifiedDate
    private LocalDateTime lastModifyDate;

    @CreatedBy
    private String createBy;

    @LastModifiedBy
    private String LastModifiedBy;
    
}

 

상단에 @EntityListeners(AuditingEntityListener.class) 를 추가시킨다. EntityListeners는 엔티티가 불러와 질 때마다 이벤트를 발생시킨다.

 

날짜도 날짜지만, 등록자,수정자는 어디서 가지고 올 수 있는가?

 

package study.datajpa;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.data.domain.AuditorAware;
import org.springframework.data.jpa.repository.config.EnableJpaAuditing;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;

import java.util.Optional;
import java.util.UUID;

@EnableJpaAuditing
@SpringBootApplication
public class DataJpaApplication {

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

	@Bean
	public AuditorAware<String> auditorProvider(){
		return () -> Optional.of(UUID.randomUUID().toString());
	}
}

 

스프링 부트 설정 클래스에 auditorProvider를 작성한다. 예제라 uuid를 사용했는데, 실제로는 스프링 시큐리티에서 id를 빼와야 할 것이다.

 

만약! 등록시에 수정일을 넣고싶지 않다면 (null처리를 하고싶다면)

@EnableJpaAuditing(modifyOnCreate = false)
@SpringBootApplication
public class DataJpaApplication {

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

	@Bean
	public AuditorAware<String> auditorProvider(){
		return () -> Optional.of(UUID.randomUUID().toString());
	}
}

 

modifyOnCreate = false 옵션을 사용하면 된다.

 

하지만 거의 실무에서는 수정일에 Null을 넣는 일은 거의 없다..

 

 

 

만약!

테이블에 따라서 등록자, 수정자가 필요가 없다면

package study.datajpa.entity;

import jakarta.persistence.Column;
import jakarta.persistence.EntityListeners;
import jakarta.persistence.MappedSuperclass;
import lombok.Getter;
import org.springframework.data.annotation.CreatedDate;
import org.springframework.data.annotation.LastModifiedDate;
import org.springframework.data.jpa.domain.support.AuditingEntityListener;

import java.time.LocalDateTime;

@EntityListeners(AuditingEntityListener.class)
@Getter
@MappedSuperclass
public class BaseTimeEntity {

    @CreatedDate
    @Column(updatable = false)
    private LocalDateTime createDate;

    @LastModifiedDate
    private LocalDateTime lastModifyDate;

}

 

package study.datajpa.entity;

import jakarta.persistence.Column;
import jakarta.persistence.EntityListeners;
import jakarta.persistence.MappedSuperclass;
import lombok.Getter;
import org.springframework.context.event.EventListener;
import org.springframework.data.annotation.CreatedBy;
import org.springframework.data.annotation.CreatedDate;
import org.springframework.data.annotation.LastModifiedBy;
import org.springframework.data.annotation.LastModifiedDate;
import org.springframework.data.jpa.domain.support.AuditingEntityListener;

import java.time.LocalDateTime;

@EntityListeners(AuditingEntityListener.class)
@Getter
@MappedSuperclass
public class BaseEntity extends BaseTimeEntity {

    @CreatedBy
    private String createBy;

    @LastModifiedBy
    private String LastModifiedBy;

}

 

BaseTimeEntity를 따로두어 BaseEntity 최상위에 넣고 따로 사용해도 된다. (김영한 개발자님 꿀팁)

공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/10   »
1 2 3 4 5
6 7 8 9 10 11 12
13 14 15 16 17 18 19
20 21 22 23 24 25 26
27 28 29 30 31
글 보관함