JPA

JPA Auditing으로 생성시간/수정시간 자동화하기

쿠카이든 2022. 2. 14. 11:38
728x90
  • 보통 Entity는 해당 데이터의 생성시간과 수정시간을 포함하고 있다. 이런 정보는 추후 유지보수에 있어 굉장히 중요한 정보이기 때문이다. 이렇다 보니 DB에 삽입 및 갱신할 때는 날짜 데이터를 등록/수정하는 코드가 항상 들어가게 된다.
  //Ex. 생성일 추가
  public void savePosts() {
...
      posts.setCreateDate(new LocalDate());
      postsRepository.save(posts);
...
  }
  • 하지만 이런 코드가 모든 테이블과 서비스 메소드에 구현해야 한다면 중복이 발생하고 코드가 지저분지게 된다. 이런 문제를 해결하고자 나타난 것이 JPA Auditing이다.
  • CreateModifyTimeEntity(BaseTimeEntity)
@EntityListeners(value = {AuditingEntityListener.class})
@MappedSuperclass
public abstract class CreateModifyTimeEntity {
    @CreatedDate
    @Column(name = "created_at", updatable = false)
    private LocalDateTime createdAt;

    @LastModifiedDate
    @Column(name = "modified_at")
    private LocalDateTime modifiedAt;

    public LocalDateTime getCreatedAt() {
        return createdAt;
    }

    public LocalDateTime getModifiedAt() {
        return modifiedAt;
    }
}

사용 어노테이션설명

@MappedSuperclass
  • JPA Entity 클래스들이 BaseTimeEntity을 상속할 경우 필드들(createdAt, modifiedAt)도 컬럼으로 인식하도록 한다.
@EntityListeners(AuditingEntityListener.class)
  • BaseTimeEntity 클래스에 Auditing 기능을 포함시킨다.
@CreatedDate
  • Entity가 생성되어 저장될 때 시간이 자동 저장된다.
@LastModifiedDate
  • 조회한 Entity의 값을 변경할 때 시간이 자동 저장된다.
  • 그럼 이제 Costume 클래스(Entity 클래스)가 CreateModifyTimeEntity를 상속받도록 변경한다.
@Entity
@Table(name = "costume")
public class Costume extends CreateModifyTimeEntity {

    @Id
    @Column(name = "costume_seqno")
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @ApiModelProperty("코스튬키")
    private long costumeSeqno;

    @Column(name = "name")
    @ApiModelProperty("코스튬명")
    @StringNotEmpty
    private String name;

    @Column(name = "costume_type")
    @Convert(converter = CostumeTypeConverter.class)
    @ApiModelProperty(value = "코스튬 타입", notes = "1:한벌옷, 2:상의, 3:하의, 4:신발, 5:액세서리, 6:헤어")
    private CostumeType costumeType;
    ...
  • JPA Auditing 어노테이션들을 모두 활성화할 수 있도록 Application 클래스에 활성화 어노테이션을 추가한다.
@EnableJpaAuditing
@SpringBootApplication
public class MoonAppApiApplication {

    public static void main(String[] args) {
        SpringApplication.run(MoonAppApiApplication.class, args);
    }
}
  • Test 코드 및 결과
@SpringBootTest
@Transactional
class CostumeShopRepositoryTest {

    @Autowired
    CostumeShopRepository costumeShopRepository;

    @Test
    @DisplayName("코스튬 한벌옷 리스트 등록 성공일 때")
    void findAllSuitsActiviated() {

        LocalDateTime now = LocalDateTime.of(2022, 1,3, 0,0,0);

        Costume suit = new Costume();
        suit.setName("신사정장");
        suit.setCostumeType(CostumeType.SUIT);
        suit.setCostumeSex(CostumeSex.MALE);
        suit.setCoin(150);
        suit.setJewel(1);
        suit.setSaveRate(0.05f);
        suit.setDiscountRate(0.1f);
        suit.setCostumeActiveYn(CostumeActiveYn.Yes);
        suit.setDescription("멋있는 신사정장");

        //when - 한벌옷을 등록하는 메서드를 실행한다.
        Costume saveResult = costumeShopRepository.save(suit);

        //then - save함수를 통해 저장이 되는지 확인
        assertThat(saveResult.getCostumeSeqno()).isNotNull();
        assertThat(saveResult.getCostumeSeqno()).isGreaterThan(0L);
        assertThat(saveResult.getCostumeType()).isEqualTo(CostumeType.SUIT);
        assertThat(saveResult.getCostumeSex()).isEqualTo(CostumeSex.MALE);
        assertThat(saveResult.getCoin()).isEqualTo(150);
        assertThat(saveResult.getJewel()).isEqualTo(1);
        assertThat(saveResult.getSaveRate()).isEqualTo(0.05f);
        assertThat(saveResult.getDiscountRate()).isEqualTo(0.1f);
        assertThat(saveResult.getCostumeActiveYn()).isEqualTo(CostumeActiveYn.Yes);
        assertThat(saveResult.getDescription()).isEqualTo("멋있는 신사정장");
        assertThat(saveResult.getCreatedAt()).isAfter(now);
        assertThat(saveResult.getModifiedAt()).isAfter(now);

        System.out.println(">>>>>>>>> createDate=" + saveResult.getCreatedAt() + ", modifiedDate = " + saveResult.getModifiedAt() + "<<<<<<<<<<");
    }
}
생성, 수정시간 자동 가져오기 결과
728x90