티스토리 뷰
등록 수정에 대한 내용이 없으면 유지보수 등 나중에 확인할 때에 문제가 생길 수도 있다. 김영한개발자님은 모든 테이블에 등록, 수정 내용을 꼭 남긴다고 한다.
같은 데이터의 모양이므로 하나의 클래스로 진행한다. 실무에서도 자주 쓰는 기술이라 한다.
순수 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 최상위에 넣고 따로 사용해도 된다. (김영한 개발자님 꿀팁)
'dev_공부일지 > spring data JPA' 카테고리의 다른 글
Web 확장 - 페이징과 정렬 (0) | 2024.03.06 |
---|---|
Web확장 도메인 클래스 컨버터 (@Pathvariable 객체로 받기) (0) | 2024.03.06 |
확장 기능 - 사용자 정의 레퍼지토리 (0) | 2024.03.06 |
JPA Hint & Lock (0) | 2024.03.06 |
@EntityGraph (0) | 2024.03.06 |
- Total
- Today
- Yesterday
- SpringBoot
- 향해플러스
- 백엔드 개발자 공부
- jpa api
- 스프링공부
- hypertexttransferprotocol
- filter
- 항해99
- 인터셉터
- JPA
- 항해플러스
- exception
- rejectValue
- React
- thymleaf
- 백엔드 개발자 역량
- 로그인
- ArgumentResolver
- reject
- 향해플러스백엔드
- HTTP
- Java
- 향해99
- 컨트
- 리터럴
- react실행
- 예외처리
- Intercepter
- BindingResult
- 스프링부트
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |