5.1 Tidspunkt for endring av data

Når du lagrer ulike poster i en database i mange år, oppstår ofte to spørsmål:

  • Når ble denne oppføringen lagt til databasen?
  • Når ble denne oppføringen sist endret?

Dette er så hyppige oppgaver at to kolonner legges til i nesten hver tabell i databasen:

  • opprettet_tid
  • oppdatert_tid

Den første lagrer datoen og klokkeslettet da posten ble opprettet, og den andre lagrer datoen og klokkeslettet den sist ble endret. Og hver Entity-klasse har felt:


@Entity
@Table(name = "entities")	
public class Entity {
  ...
 
  @Column(name="created_time")
  private Date created;
 
  @Column(name="updated_time")
  private Date updated;
}

Hibernate kan gjøre alt arbeidet med å kontrollere når objekter i databasen oppdateres med to merknader @CreationTimestampog @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;
}

Kolonnene merket med disse merknadene vil alltid lagre riktig tidspunkt da objektet ble opprettet og når det sist ble endret.

5.2 @PrePersist-kommentar

Hvis du trenger noen mer komplekse skript for å kontrollere tidspunktet for et objekt, så har Hibernate merknader for denne saken også. De kan merke klassemetoder, og Hibernate kaller disse metodene når den lagrer objektet i databasen. Det er 7 slike merknader totalt:

@PrePersist Kalles før objektet er lagret i databasen. (SQL INSERT)
@PostPersist Kalt opp umiddelbart etter at objektet er lagret i databasen. (SQL INSERT)
@Forhåndsfjern Kalt før sletting av et objekt i databasen.
@PostRemove Kalt opp etter at et objekt er slettet fra databasen.
@Forhåndsoppdatering Kalt før oppdatering (SQL UPDATE) et objekt i databasen.
@PostUpdate Kalt etter en oppdatering (SQL UPDATE) av et objekt i databasen.
@PostLoad Kalt opp etter at objektet er lastet inn fra databasen.

La oss skrive et eksempel der vi forteller en klasse riktig tidspunkt for å opprette og oppdatere objektene:

@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 lagrer objektet for første gang, vil det kalle opp metoden som er kommentert med @PrePersist. Hvis den oppdaterer et eksisterende objekt i databasen, vil den kalle opp metoden merket med merknaden @PreUpdate.

5.3 Legge til våre EntityListeners

Hvis du virkelig trenger det, kan du skille metodene som Hibernate kaller fra objektet den kaller dem på. JPA-spesifikasjonen lar deg deklarere lytterklasser som vil bli kalt til bestemte tider ved behandling av enhetsobjekter.

Hvis du har mange lignende Entity-objekter, kan du flytte noen av dem inn i basisklassen og legge til en Listener som kontrollerer oppførselen deres. 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 opprette en spesiell 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 koble brukerklassen og dens lytter ved å bruke et par merknader:


@Entity
@EntityListeners(class= TimeEntityListener.class)
public class User extends BaseEntity {
 
     @Id
     private Long id;
 
     private String name;
}