JPA Auditingとは
JPAを使用してDomainをRDBSのテーブルにマッピングする際、共通的にDomainを持っているフィールドやカラムが存在します。
代表的には以下となります。
- CreateDate
- UpdateDate
- 識別子
のようなフィールドおよびカラムがありますよね。
Domainごとに存在するということはコードが重複されていることでしょう。
データベースを誰が、いつ作成したのかなど記録を残したほうがメンテナンスにも役に立つためです。
そのため、生成日、修正日のようなカラムは本当に重要なデータです。
それでJPAではAuditという機能を提供しています。Auditは監視するという意味でSpring Data JPAで時間に対して自動的に値を入れてくれる機能です。ドメインを永続性コンテキストに保存したり照会などを行ってからupdateを行う場合、毎回時間データを入力しなければならないのですが、auditを利用することで自動的に時間をマッピングしデータベースのテーブルに入れてくれます。
練習
1.domain package内にBaseTimeEntityクラスを作ります。
2.BaseTimeEntityを以下のように作成します。
package jojoidu.boot.springboot.domain;
import lombok.Getter;
import org.springframework.data.annotation.CreatedDate;
import org.springframework.data.annotation.LastModifiedDate;
import org.springframework.data.jpa.domain.support.AuditingEntityListener;
import javax.persistence.EntityListeners;
import javax.persistence.MappedSuperclass;
import java.time.LocalDateTime;
@Getter
@MappedSuperclass
@EntityListeners(AuditingEntityListener.class)
public abstract class BaseTimeEntity {
@CreatedDate
private LocalDateTime createdDate;
@LastModifiedDate
private LocalDateTime modifiedDate;
}
BaseTimeEntityクラスはすべてのEntityクラスの親クラスになり、EntityクラスのcreatedDate、modifiedDateを自動で管理する役割をします。
-
@MappedSuperclass
- JPA EntityクラスがBaseTimeEntityを継承する場合フィールド(createdDate、modifiedDate)もカラムとして認識されるようにします。
-
@EntityListeners(AuditingEntityListener.class)
- BaseTimeEntityクラスにAuditing機能を与えます。
-
@CreatedDate
- Entityが生成され、保存されるとき時間が自動に保存されます。
-
@LastModifiedDate
- 照会したEntityの値を変更する際、時間が自動に保存されます。
3.EntityクラスにBaseTimeEntityクラスを継承します。
package jojoidu.boot.springboot.domain.posts;
import jojoidu.boot.springboot.domain.BaseTimeEntity;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;
import javax.persistence.*;
@Getter
@NoArgsConstructor
@Entity // テーブルとリンクされるクラスを示す
public class Posts extends BaseTimeEntity {
@Id // PKフィールドを示す
@GeneratedValue(strategy = GenerationType.IDENTITY)
private long id;
@Column(length = 500, nullable = false)
private String title;
@Column(columnDefinition = "TEXT", nullable = false)
private String content;
private String author;
@Builder
public Posts(String title, String content, String author) {
this.title = title;
this.content = content;
this.author = author;
}
public void update(String title, String content) {
this.title = title;
this.content = content;
}
}
4.最後にJPA Auditingアノテーションが活性化されるようにmainクラスに活性化アノテーションを追加します。
package jojoidu.boot.springboot;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.data.jpa.repository.config.EnableJpaAuditing;
@EnableJpaAuditing
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
テスト
テストは欠かせないので、テストメソッドも追加してみました。
@Test
public void saveBaseTimeEntity() {
// given
LocalDateTime now = LocalDateTime.of(2020, 8,12,0,0,0);
postsRepository.save(Posts.builder()
.title("title")
.content("content")
.author("author")
.build());
// when
List<Posts> postsList = postsRepository.findAll();
//then
Posts posts = postsList.get(0);
System.out.println(">>>>>>>createdDate=" + posts.getCreatedDate() + ", modifiedDate=" + posts.getModifiedDate());
assertThat(posts.getCreatedDate()).isAfter(now);
assertThat(posts.getModifiedDate()).isAfter(now);
}