Entity를 DB에 적용하기 전, 후로 커스텀 콜백을 요청하는 어노테이션이 있습니다.
@PrePersist
@PostPersist
@PostLoad
@PreUpdate
@PostUpdate
@PreRemove
@PostRemove
어노테이션 이름으로 유추해 보아도 무슨 역할을 하는지 알 수 있습니다.
하나씩 살펴보겠습니다.
@PrePersist & @PostPersist
@Slf4j
@Entity
@Builder
@Getter
@Table(name = "postMst")
public class Post extends BaseTimeEntity {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long postCode;
@NotNull
@Column(name = "postContent")
private String content;
@PrePersist
private void logInfo() {
log.info("INSERT 전에 호출되었습니다.");
}
@PostPersist
private void logPostCode() {
log.info("postCode: {}", postCode);
}
}
@PrePersist는 DB에 INSERT가 되기 전에 호출되고 @PostPersist는 INSERT 후에 호출이 됩니다.
@Test
void savePostTest() {
// given
Post post = Post.builder()
.content("게시글5")
.build();
// when
postService.savePost(post);
// then
}
@Transactional
public void savePost(Post post) {
entityManager.persist(post);
}
2023-01-14 21:23:49.320 INFO 16584 --- [ main] com.project.instagram.domain.test.Post : INSERT 전에 호출되었습니다.
Hibernate:
/* insert com.project.instagram.domain.test.Post
*/ insert
into
post_mst
(create_date, update_date, post_content)
values
(?, ?, ?)
2023-01-14 21:23:49.407 INFO 16584 --- [ main] com.project.instagram.domain.test.Post : postCode: 5
테스트코드를 작성하고 실행해보았습니다.
로그를 보면 INSERT가 일어나기 전에 로그가 하나 찍히고 INSERT가 일어난 후에 로그가 하나 찍혔습니다.
Post 객체의 postCode는 AutoIncreament 된 값으로 확인할 수 있습니다.
@PostLoad
@Slf4j
@Entity
@Builder
@Getter
@NoArgsConstructor
@AllArgsConstructor
@Table(name = "postMst")
public class Post extends BaseTimeEntity {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long postCode;
@NotNull
@Column(name = "postContent")
private String content;
@PostLoad
private void logInfo() {
log.info("SELECT 이후에 호출되었습니다.");
}
}
DB에서 SELECT 후에 호출하기 위해 사용하는 어노테이션입니다.
Hibernate:
select
post0_.post_code as post_cod1_10_0_,
post0_.create_date as create_d2_10_0_,
post0_.update_date as update_d3_10_0_,
post0_.post_content as post_con4_10_0_
from
post_mst post0_
where
post0_.post_code=?
2023-01-14 21:33:19.176 INFO 1752 --- [ main] com.project.instagram.domain.test.Post : SELECT 이후에 호출되었습니다.
역시 로그를 보면 SELECT 이후에 호출된 것을 확인할 수 있습니다.
@PreUpdate & @PostUpdate
@Slf4j
@Entity
@Builder
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
@Table(name = "postMst")
public class Post extends BaseTimeEntity {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long postCode;
@NotNull
@Column(name = "postContent")
private String content;
@PreUpdate
private void logDefaultContent() {
log.info("content: {}", content);
}
@PostUpdate
private void logNewContent() {
log.info("content: {}", content);
}
}
@PreUpdate: DB에서 UPDATE가 일어나기 전에 호출되게끔 하는 어노테이션
@PostUpdate: DB에서 UPDATE가 일어난 후에 호출되게끔 하는 어노테이션
@Transactional
public void updatePost(Long postCode, String content) {
Post post = entityManager.find(Post.class, postCode);
post.setContent(content);
}
2023-01-14 21:39:06.744 INFO 4424 --- [ main] com.project.instagram.domain.test.Post : content: 업데이트한 게시글입니다.
Hibernate:
/* update
com.project.instagram.domain.test.Post */ update
post_mst
set
create_date=?,
update_date=?,
post_content=?
where
post_code=?
2023-01-14 21:39:06.853 INFO 4424 --- [ main] com.project.instagram.domain.test.Post : content: 업데이트한 게시글입니다.
여기서 우리가 주의해야 할 것이 있습니다.
로그를 보면 UPDATE가 일어나기 전, 후로 로그는 잘 나왔습니다.
하지만 제가 의도한 것은 수정되기 전의 content를 @PreUpdate로 로그를 찍어보는 것과
수정된 후의 content를 @PostUpdate로 로그를 찍어보는 것입니다.
하지만 결과는 둘 다 수정된 후의 content 내용이 찍혔습니다.
이유는 더티체킹으로 UPDATE가 일어나서 그런 것입니다.
더티체킹은 트랜잭션 안에서 커밋이 되고 난 후에 일어납니다.
지금 @Transactional 어노테이션을 달아놓았기 때문에 메서드 호출 마지막에 커밋이 일어나서
이미 Post 객체의 content는 setter로 값을 바꾼 뒤이기 때문에 의도한 대로 작동하지 않았습니다.
@PreRemove & @PostRemove
@Slf4j
@Entity
@Builder
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
@Table(name = "postMst")
public class Post extends BaseTimeEntity {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long postCode;
@NotNull
@Column(name = "postContent")
private String content;
@PreRemove
private void logInfo() {
log.info("DELETE 전");
}
@PostRemove
private void logInfo2() {
log.info("DELETE 후");
}
}
@PreRemove: DB에서 DELETE가 일어나기 전에 호출되게끔 하는 어노테이션
@PostRemove: DB에서 DELETE가 일어난 후에 호출되게끔 하는 어노테이션
2023-01-14 21:49:19.896 INFO 18612 --- [ main] com.project.instagram.domain.test.Post : DELETE 전
Hibernate:
/* delete com.project.instagram.domain.test.Post */ delete
from
post_mst
where
post_code=?
2023-01-14 21:49:19.934 INFO 18612 --- [ main] com.project.instagram.domain.test.Post : DELETE 후
'DB > JPA' 카테고리의 다른 글
JPA 즉시 로딩, 지연 로딩 (0) | 2023.01.20 |
---|---|
JPA Auditing (0) | 2023.01.07 |
JPA @Entity (0) | 2023.01.06 |
JPA DTO Mapping (0) | 2022.12.29 |
JPA 더티 체킹(Dirty Checking) (0) | 2022.12.25 |
댓글