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 TIMESTAMP
verschiebt 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 DATETIME
stattdessen besser , da diese Obergrenze nicht begrenzt ist. Allerdings DATETIME
ist nicht bekannt , Zeitzone. Aus diesem Grund ist es am besten, UTC auf der Datenbankseite zu verwenden und die hibernate.jdbc.time_zone
Eigenschaft Hibernate zu verwenden.
Weitere Informationen zur hibernate.jdbc.time_zone
Einstellung 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 LocalDateTime
oder java.sql.Timestamp
zum @Temporal
Zuordnen 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 @Temporal
Anmerkung 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_on
Spalte können Sie eine DEFAULT
DDL-Einschränkung verwenden, z.
ALTER TABLE post
ADD CONSTRAINT created_on_default
DEFAULT CURRENT_TIMESTAMP() FOR created_on;
Für die updated_on
Spalte 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 @CreationTimestamp
und von @UpdateTimestamp
Anmerkungen
Der Ruhezustand bietet die Anmerkungen @CreationTimestamp
und @UpdateTimestamp
, mit denen die Spalten created_on
und zugeordnet werden updated_on
können.
Sie können @MappedSuperclass
eine 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 BaseEntity
wie 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 @MappedSuperclass
finden Sie in diesem Artikel .
Selbst wenn die Eigenschaften createdOn
und updateOn
durch die Ruhezustandsspezifischen @CreationTimestamp
und @UpdateTimestamp
Anmerkungen festgelegt werden, müssen für createdBy
und updatedBy
ein 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 @EntityListeners
JPA-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 @EntityListener
finden Sie in diesem Artikel .