5.1 Zeitpunkt der Datenänderung
Wenn Sie verschiedene Datensätze über viele Jahre in einer Datenbank speichern, stellen sich häufig zwei Fragen:
- Wann wurde dieser Eintrag zur Datenbank hinzugefügt?
- Wann wurde dieser Eintrag zuletzt geändert?
Dies sind so häufige Aufgaben, dass fast jeder Tabelle in der Datenbank zwei Spalten hinzugefügt werden:
- erstellte_Zeit
- aktualisierte_Zeit
Der erste speichert das Datum und die Uhrzeit, zu der der Datensatz erstellt wurde, und der zweite speichert das Datum und die Uhrzeit, zu der er zuletzt geändert wurde. Und jede Entity-Klasse hat Felder:
@Entity
@Table(name = "entities")
public class Entity {
...
@Column(name="created_time")
private Date created;
@Column(name="updated_time")
private Date updated;
}
@CreationTimestamp
Hibernate kann die gesamte Arbeit der Steuerung übernehmen, wenn Objekte in der Datenbank mit zwei Anmerkungen und aktualisiert werden @UpdateTimestamp
.
Beispiel:
@Entity
@Table(name = "entities")
public class Entity {
...
@CreationTimestamp
@Temporal(TemporalType.TIMESTAMP)
@Column(name = "create_date")
private Date createDate;
@UpdateTimestamp
@Temporal(TemporalType.TIMESTAMP)
@Column(name = "modify_date")
private Date modifyDate;
}
Die mit diesen Anmerkungen gekennzeichneten Spalten speichern immer den korrekten Zeitpunkt, zu dem das Objekt erstellt und zuletzt geändert wurde.
5.2 @PrePersist-Annotation
Wenn Sie komplexere Skripte benötigen, um die Zeit eines Objekts zu steuern, bietet Hibernate auch für diesen Fall Anmerkungen. Sie können Klassenmethoden markieren, und Hibernate ruft diese Methoden auf, wenn das Objekt in der Datenbank gespeichert wird. Insgesamt gibt es 7 solcher Anmerkungen:
@PrePersist | Wird aufgerufen, bevor das Objekt in der Datenbank gespeichert wird. (SQL-INSERT) |
@PostPersist | Wird unmittelbar nach dem Speichern des Objekts in der Datenbank aufgerufen. (SQL-INSERT) |
@PreRemove | Wird vor dem Löschen eines Objekts in der Datenbank aufgerufen. |
@PostRemove | Wird aufgerufen, nachdem ein Objekt aus der Datenbank gelöscht wurde. |
@PreUpdate | Wird vor dem Aktualisieren (SQL UPDATE) eines Objekts in der Datenbank aufgerufen. |
@PostUpdate | Wird nach einer Aktualisierung (SQL UPDATE) eines Objekts in der Datenbank aufgerufen. |
@PostLoad | Wird aufgerufen, nachdem das Objekt aus der Datenbank geladen wurde. |
Schreiben wir ein Beispiel, in dem wir einer Klasse den richtigen Zeitpunkt zum Erstellen und Aktualisieren ihrer Objekte mitteilen:
@Entity
@Table(name = "entities")
public class Entity {
...
@Column(name="created_time")
private Date created;
@Column(name="updated_time")
private Date updated;
@PrePersist
protected void onCreate() {
created = new Date();
}
@PreUpdate
protected void onUpdate() {
updated = new Date();
}
}
Wenn Hibernate das Objekt zum ersten Mal speichert, ruft es die mit annotierte Methode auf @PrePersist
. Wenn ein vorhandenes Objekt in der Datenbank aktualisiert wird, ruft es die mit der Annotation gekennzeichnete Methode auf @PreUpdate
.
5.3 Hinzufügen unserer EntityListener
Wenn es wirklich nötig ist, können Sie die Methoden, die Hibernate aufruft, von dem Objekt trennen, für das sie aufgerufen werden. Mit der JPA-Spezifikation können Sie Listener-Klassen deklarieren, die zu bestimmten Zeiten bei der Verarbeitung von Entity-Objekten aufgerufen werden.
Wenn Sie viele ähnliche Entity-Objekte haben, können Sie einige davon in die Basisklasse verschieben und einen Listener hinzufügen, der ihr Verhalten steuert. Beispiel:
@MappedSuperclass
public abstract class BaseEntity {
private Timestamp createdOn;
private Timestamp updatedOn;
}
@Entity
public class User extends BaseEntity {
@Id
private Long id;
private String name;
}
Dann können Sie für die BaseEntity-Klasse eine spezielle Listener-Klasse erstellen:
public class TimeEntityListener {
public void onPersist(Object entity) {
if (entity instanceof BaseEntity) {
BaseEntity baseEntity = (BaseEntity) entity;
baseEntity.createdOn = now();
}
}
public void onUpdate(Object entity) {
if (entity instanceof BaseEntity) {
BaseEntity baseEntity = (BaseEntity) entity;
baseEntity.updatedOn = now();
}
}
private Timestamp now() {
return Timestamp.from(LocalDateTime.now().toInstant(ZoneOffset.UTC) );
}
}
Und Sie können die User-Klasse und ihren Listener mithilfe einiger Anmerkungen verbinden:
@Entity
@EntityListeners(class= TimeEntityListener.class)
public class User extends BaseEntity {
@Id
private Long id;
private String name;
}