1. Welche Datenbankspaltentypen sollten Sie verwenden?
Ihre erste Frage war:
Welche Datentypen würden Sie in der Datenbank verwenden (unter der Annahme von MySQL, möglicherweise in einer anderen Zeitzone als die JVM)? Werden die Datentypen zeitzonenabhängig sein?
In MySQL TIMESTAMPverschiebt der Spaltentyp von der lokalen Zeitzone des JDBC-Treibers in die Datenbank-Zeitzone, kann jedoch nur Zeitstempel bis zu speichern '2038-01-19 03:14:07.999999, sodass dies nicht die beste Wahl für die Zukunft ist.
Verwenden Sie DATETIMEstattdessen besser , da diese Obergrenze nicht begrenzt ist. Allerdings DATETIMEist nicht bekannt , Zeitzone. Aus diesem Grund ist es am besten, UTC auf der Datenbankseite zu verwenden und die hibernate.jdbc.time_zoneEigenschaft Hibernate zu verwenden.
Weitere Informationen zur hibernate.jdbc.time_zoneEinstellung finden Sie in diesem Artikel .
2. Welchen Entitätseigenschaftstyp sollten Sie verwenden?
Ihre zweite Frage war:
Welche Datentypen würden Sie in Java verwenden (Datum, Kalender, lang, ...)?
Auf der Java-Seite können Sie Java 8 verwenden LocalDateTime. Sie können auch das Legacy verwenden Date, aber die Java 8-Datums- / Zeittypen sind besser, da sie unveränderlich sind und beim Protokollieren keine Zeitzonenverschiebung in die lokale Zeitzone durchführen.
Weitere Informationen zu den von Hibernate unterstützten Java 8-Datums- / Uhrzeittypen finden Sie in diesem Artikel .
Jetzt können wir auch diese Frage beantworten:
Welche Anmerkungen würden Sie für das Mapping verwenden (z. B. @Temporal)?
Wenn Sie die Eigenschaft LocalDateTimeoder java.sql.Timestampzum @TemporalZuordnen einer Zeitstempel-Entitätseigenschaft verwenden, müssen Sie diese nicht verwenden, da HIbernate bereits weiß, dass diese Eigenschaft als JDBC-Zeitstempel gespeichert werden soll.
Nur wenn Sie verwenden java.util.Date, müssen Sie die @TemporalAnmerkung wie folgt angeben :
@Temporal(TemporalType.TIMESTAMP)
@Column(name = "created_on")
private Date createdOn;
Aber es ist viel besser, wenn Sie es so abbilden:
@Column(name = "created_on")
private LocalDateTime createdOn;
So generieren Sie die Prüfspaltenwerte
Ihre dritte Frage war:
Wen würden Sie für das Festlegen der Zeitstempel verantwortlich machen - die Datenbank, das ORM-Framework (Ruhezustand) oder den Anwendungsprogrammierer?
Welche Anmerkungen würden Sie für das Mapping verwenden (z. B. @Temporal)?
Es gibt viele Möglichkeiten, wie Sie dieses Ziel erreichen können. Sie können der Datenbank erlauben, dies zu tun.
Für die create_onSpalte können Sie eine DEFAULTDDL-Einschränkung verwenden, z.
ALTER TABLE post
ADD CONSTRAINT created_on_default
DEFAULT CURRENT_TIMESTAMP() FOR created_on;
Für die updated_onSpalte können Sie einen DB-Trigger verwenden, um den Spaltenwert mit festzulegenCURRENT_TIMESTAMP() jeder Änderung einer bestimmten Zeile festzulegen.
Oder verwenden Sie JPA oder Hibernate, um diese festzulegen.
Angenommen, Sie haben die folgenden Datenbanktabellen:

Und jede Tabelle hat Spalten wie:
created_by
created_on
updated_by
updated_on
Verwenden des Ruhezustands @CreationTimestampund von @UpdateTimestampAnmerkungen
Der Ruhezustand bietet die Anmerkungen @CreationTimestampund @UpdateTimestamp, mit denen die Spalten created_onund zugeordnet werden updated_onkönnen.
Sie können @MappedSuperclasseine Basisklasse definieren, die von allen Entitäten erweitert wird:
@MappedSuperclass
public class BaseEntity {
@Id
@GeneratedValue
private Long id;
@Column(name = "created_on")
@CreationTimestamp
private LocalDateTime createdOn;
@Column(name = "created_by")
private String createdBy;
@Column(name = "updated_on")
@UpdateTimestamp
private LocalDateTime updatedOn;
@Column(name = "updated_by")
private String updatedBy;
//Getters and setters omitted for brevity
}
Und alle Entitäten werden das BaseEntitywie folgt erweitern :
@Entity(name = "Post")
@Table(name = "post")
public class Post extend BaseEntity {
private String title;
@OneToMany(
mappedBy = "post",
cascade = CascadeType.ALL,
orphanRemoval = true
)
private List<PostComment> comments = new ArrayList<>();
@OneToOne(
mappedBy = "post",
cascade = CascadeType.ALL,
orphanRemoval = true,
fetch = FetchType.LAZY
)
private PostDetails details;
@ManyToMany
@JoinTable(
name = "post_tag",
joinColumns = @JoinColumn(
name = "post_id"
),
inverseJoinColumns = @JoinColumn(
name = "tag_id"
)
)
private List<Tag> tags = new ArrayList<>();
//Getters and setters omitted for brevity
}
Weitere Informationen zur Verwendung @MappedSuperclassfinden Sie in diesem Artikel .
Selbst wenn die Eigenschaften createdOnund updateOndurch die Ruhezustandsspezifischen @CreationTimestampund @UpdateTimestampAnmerkungen festgelegt werden, müssen für createdByund updatedByein Anwendungsrückruf registriert werden, wie in der folgenden JPA-Lösung dargestellt.
Verwenden von JPA @EntityListeners
Sie können die Überwachungseigenschaften in eine eingebettete Datei einkapseln:
@Embeddable
public class Audit {
@Column(name = "created_on")
private LocalDateTime createdOn;
@Column(name = "created_by")
private String createdBy;
@Column(name = "updated_on")
private LocalDateTime updatedOn;
@Column(name = "updated_by")
private String updatedBy;
//Getters and setters omitted for brevity
}
Erstellen Sie eine AuditListener, um die Überwachungseigenschaften festzulegen:
public class AuditListener {
@PrePersist
public void setCreatedOn(Auditable auditable) {
Audit audit = auditable.getAudit();
if(audit == null) {
audit = new Audit();
auditable.setAudit(audit);
}
audit.setCreatedOn(LocalDateTime.now());
audit.setCreatedBy(LoggedUser.get());
}
@PreUpdate
public void setUpdatedOn(Auditable auditable) {
Audit audit = auditable.getAudit();
audit.setUpdatedOn(LocalDateTime.now());
audit.setUpdatedBy(LoggedUser.get());
}
}
Um das zu registrieren AuditListener, können Sie die @EntityListenersJPA-Anmerkung verwenden:
@Entity(name = "Post")
@Table(name = "post")
@EntityListeners(AuditListener.class)
public class Post implements Auditable {
@Id
private Long id;
@Embedded
private Audit audit;
private String title;
@OneToMany(
mappedBy = "post",
cascade = CascadeType.ALL,
orphanRemoval = true
)
private List<PostComment> comments = new ArrayList<>();
@OneToOne(
mappedBy = "post",
cascade = CascadeType.ALL,
orphanRemoval = true,
fetch = FetchType.LAZY
)
private PostDetails details;
@ManyToMany
@JoinTable(
name = "post_tag",
joinColumns = @JoinColumn(
name = "post_id"
),
inverseJoinColumns = @JoinColumn(
name = "tag_id"
)
)
private List<Tag> tags = new ArrayList<>();
//Getters and setters omitted for brevity
}
Weitere Informationen zum Implementieren von Audit-Eigenschaften mit dem JPA @EntityListenerfinden Sie in diesem Artikel .