5.1 Tidspunkt for dataændring
Når du gemmer forskellige poster i en database i mange år, opstår der ofte to spørgsmål:
- Hvornår blev denne post tilføjet til databasen?
- Hvornår blev denne post sidst ændret?
Disse er så hyppige opgaver, at der tilføjes to kolonner til næsten hver tabel i databasen:
- oprettet_tid
- updated_time
Den første gemmer datoen og klokkeslættet, da posten blev oprettet, og den anden gemmer datoen og klokkeslættet, hvor den sidst blev ændret. Og hver enhedsklasse har felter:
@Entity
@Table(name = "entities")
public class Entity {
...
@Column(name="created_time")
private Date created;
@Column(name="updated_time")
private Date updated;
}
Hibernate kan klare alt arbejdet med at kontrollere, hvornår objekter i databasen opdateres med to anmærkninger @CreationTimestamp
og @UpdateTimestamp
.
Eksempel:
@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;
}
Kolonnerne markeret med disse anmærkninger vil altid gemme det korrekte tidspunkt, da objektet blev oprettet, og hvornår det sidst blev ændret.
5.2 @PrePersist annotation
Hvis du har brug for nogle mere komplekse scripts til at kontrollere tidspunktet for et objekt, så har Hibernate også anmærkninger til denne sag. De kan markere klassemetoder, og Hibernate kalder disse metoder, når den gemmer objektet i databasen. Der er 7 sådanne anmærkninger i alt:
@PrePersist | Kaldes før objektet gemmes i databasen. (SQL INDSÆT) |
@PostPersist | Kaldes umiddelbart efter, at objektet er gemt i databasen. (SQL INDSÆT) |
@Forudfjern | Kaldes før sletning af et objekt i databasen. |
@PostRemove | Kaldes efter et objekt er blevet slettet fra databasen. |
@PreUpdate | Kaldes før opdatering (SQL UPDATE) et objekt i databasen. |
@PostUpdate | Kaldes efter en opdatering (SQL UPDATE) af et objekt i databasen. |
@PostLoad | Kaldes efter objektet er blevet indlæst fra databasen. |
Lad os skrive et eksempel, hvor vi fortæller en klasse det rigtige tidspunkt for at oprette og opdatere dens objekter:
@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();
}
}
Hvis Hibernate gemmer objektet for første gang, kalder det metoden, der er kommenteret med @PrePersist
. Hvis den opdaterer et eksisterende objekt i databasen, kalder den metoden, der er markeret med annotationen @PreUpdate
.
5.3 Tilføjelse af vores EntityListeners
Hvis du virkelig har brug for det, kan du adskille de metoder, som Hibernate kalder, fra det objekt, som det kalder dem på. JPA-specifikationen giver dig mulighed for at erklære lytterklasser, der vil blive kaldt på bestemte tidspunkter, når du behandler enhedsobjekter.
Hvis du har mange lignende Entity-objekter, kan du flytte nogle af dem ind i basisklassen og tilføje en Listener, der kan kontrollere deres adfærd. Eksempel:
@MappedSuperclass
public abstract class BaseEntity {
private Timestamp createdOn;
private Timestamp updatedOn;
}
@Entity
public class User extends BaseEntity {
@Id
private Long id;
private String name;
}
Så for BaseEntity-klassen kan du oprette en speciel lytterklasse:
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) );
}
}
Og du kan forbinde brugerklassen og dens lytter ved hjælp af et par anmærkninger:
@Entity
@EntityListeners(class= TimeEntityListener.class)
public class User extends BaseEntity {
@Id
private Long id;
private String name;
}