JPA Auditing 커스텀 & queryDSL
JPA Auditing 이란?
-
Java에서 ORM 기술인 JPA를 사용하여 도메인을 관계형 데이터베이스 테이블에 매핑할 때 공통적으로 도메인들이 가지고 있는 필드나 컬럼들이 존재합니다. 대표적으로 생성일자, 수정일자, 식별자 같은 필드 및 컬럼이 있습니다.
-
도메인마다 공통으로 존재한다는 의미는 결국 코드가 중복된다는 말과 일맥상통합니다.
데이터베이스에서 누가, 언제하였는지 기록을 잘 남겨놓아야 합니다. 그렇기 때문에 생성일, 수정일 컬럼은 대단히 중요한 데이터 입니다. -
그래서 JPA에서는 Audit이라는 기능을 제공하고 있습니다. Audit은 감시하다, 감사하다라는 뜻으로 Spring Data JPA에서 시간에 대해서 자동으로 값을 넣어주는 기능입니다. 도메인을 영속성 컨텍스트에 저장하거나 조회를 수행한 후에 update를 하는 경우 매번 시간 데이터를 입력하여 주어야 하는데, audit을 이용하면 자동으로 시간을 매핑하여 데이터베이스의 테이블에 넣어주게 됩니다.
Audit의 단점
- Jpa Auditing을 사용하기 위해서는
상속
을 받아야한다.
public class User extends BaseEntity
- 하지만
상속
은 다중 상속이 안되고, 최대한 상속을 피하기 위해 다음과 같이 Auditing을 커스텀해서 만들어 보았다.
AuditListener
- Auditable 인터페이스 생성
public interface Auditable {
TimeEntity getTimeEntity();
void setTimeEntity(TimeEntity timeEntity);
}
@Configuration
public class AuditListener {
@PrePersist
public void setCreateDate(Auditable auditable) {
TimeEntity timeEntity = auditable.getTimeEntity();
if (timeEntity == null) {
timeEntity = new TimeEntity();
auditable.setTimeEntity(timeEntity);
}
timeEntity.setCreatedDate(LocalDateTime.now());
}
@PreUpdate
public void setUpdateDate(Auditable auditable){
auditable.getTimeEntity().setUpdatedDate(LocalDateTime.now());
}
}
- 위의 코드를 보면
JPA
를 다룰 줄 아는 사람이라면 이해는 했을것이다.
@Prepersist
persist가 되기 전 실행되는 어노테이션이다.
@PreUpdate
Update가 퇴기 전 실행되는 어노테이션이다.
Entity
- TimeEntity 클래스
@Getter
@Setter
@NoArgsConstructor
@Embeddable
public class TimeEntity {
@Column(updatable = false)
private LocalDateTime createdDate;
private LocalDateTime updatedDate;
}
- 사용
@Getter
@EntityListeners(AuditListener.class)
public class Post implements Auditable {
@Embeded
private TimeEntity timeentity;
public void setTimeEntity(TimeEntity timeEntity){
this.timeEntity = timeEntity;
}
}
위와 같이 실제 사용되는 엔티티 클래스에 다음과 같이 TimeEntity
를 값타입으로 넣어주었다.
- 이런식으로 상속을 받지않고
interface
구현체로 만들어서 사용할 수 있다. - 실제 사용 시 만약 Post를 만들어서
persist
를 호출하게되면 위의AuditListenr
가 동작하여 시간을createDate
를 자동으로 넣어준다.
- 위와 같이
update
가 동작하게 된다면 update 날짜를 자동으로 넣어준다.
조회수(viewCount) queryDSL
@Override
public Optional<PostOneResponse> findOnePostById(Long postId) {
queryFactory.update(post)
.set(post.viewCount, post.viewCount.add(1))
.where(post.id.eq(postId))
.execute();
return Optional.ofNullable(queryFactory
.select(new QPostOneResponse(
post.id,
post.title,
post.content,
post.timeEntity.createdDate,
post.timeEntity.updatedDate,
post.viewCount,
user.nickname))
.from(post)
.innerJoin(post.user, user)
.where(post.id.eq(postId))
.fetchOne());
}
-
필자는
queryDSL
을 사용하는데Post
에서viewCount
를 1씩 증가시켜 update 쿼리를 보내는 로직을 작성했는데 update 쿼리는 나가는데 updatedDate는 값이 들어가지 않았다. -
아마도 JPA에서
변경감지
기능은Audit
가 동작하나,queryDSL
처럼 다른 프레임워크에서 직접적으로 update 쿼리를 보내는것에서는 동작하지 않는것같다.
Author And Source
이 문제에 관하여(JPA Auditing 커스텀 & queryDSL), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://velog.io/@do-hoon/JPA-Audit-와-queryDSL저자 귀속: 원작자 정보가 원작자 URL에 포함되어 있으며 저작권은 원작자 소유입니다.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)