5.1 Tidpunkt för dataändring

När du lagrar olika poster i en databas i många år uppstår ofta två frågor:

  • När lades denna post till i databasen?
  • När ändrades denna post senast?

Dessa är så frekventa uppgifter att två kolumner läggs till i nästan varje tabell i databasen:

  • skapad_tid
  • updated_time

Den första lagrar datum och tid då posten skapades, och den andra lagrar datum och tid då den senast ändrades. Och varje Entity-klass har fält:


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

Hibernate kan göra allt arbete med att kontrollera när objekt i databasen uppdateras med två anteckningar @CreationTimestampoch @UpdateTimestamp.

Exempel:

@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;
}

Kolumnerna markerade med dessa anteckningar kommer alltid att lagra rätt tid när objektet skapades och när det senast ändrades.

5.2 @PrePersist-anteckning

Om du behöver några mer komplexa skript för att kontrollera tiden för ett objekt, så har Hibernate kommentarer för det här fallet också. De kan markera klassmetoder och Hibernate anropar dessa metoder när objektet sparas i databasen. Det finns 7 sådana kommentarer totalt:

@PrePersist Anropas innan objektet sparas i databasen. (SQL INFOGA)
@PostPersist Anropas direkt efter att objektet har sparats i databasen. (SQL INFOGA)
@PreRemove Anropas innan ett objekt tas bort i databasen.
@PostRemove Anropas efter att ett objekt har raderats från databasen.
@Föruppdatering Anropas före uppdatering (SQL UPDATE) ett objekt i databasen.
@PostUpdate Anropas efter en uppdatering (SQL UPDATE) av ett objekt i databasen.
@PostLoad Anropas efter att objektet har laddats från databasen.

Låt oss skriva ett exempel där vi talar om för en klass när den ska skapa och uppdatera dess objekt:

@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();
  }
}

Om Hibernate sparar objektet för första gången kommer det att anropa metoden som är kommenterad med @PrePersist. Om den uppdaterar ett befintligt objekt i databasen anropar den metoden som är markerad med anteckningen @PreUpdate.

5.3 Lägga till våra EntityListeners

Om du verkligen behöver kan du separera metoderna som Hibernate anropar från objektet som den anropar dem på. JPA-specifikationen låter dig deklarera lyssnarklasser som kommer att anropas vid vissa tidpunkter när entitetsobjekt bearbetas.

Om du har många liknande Entity-objekt kan du flytta några av dem till basklassen och lägga till en Listener som skulle kontrollera deras beteende. Exempel:


@MappedSuperclass
public abstract class BaseEntity {
 
    private Timestamp createdOn;
 
    private Timestamp updatedOn;
 
}


@Entity
public class User extends BaseEntity {
 
     @Id
     private Long id;
 
     private String name;
}

Sedan för BaseEntity-klassen kan du skapa en speciell lyssnarklass:


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)   );
    }
}

Och du kan koppla samman användarklassen och dess lyssnare med hjälp av ett par kommentarer:


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