5.1 Az adatváltozás időpontja

Ha sok éven át tárol különféle rekordokat egy adatbázisban, gyakran két kérdés merül fel:

  • Mikor került ez a bejegyzés az adatbázisba?
  • Mikor változtatták meg utoljára ezt a bejegyzést?

Ezek olyan gyakori feladatok, hogy az adatbázis szinte minden táblájához két oszlop kerül hozzáadásra:

  • létre_idő
  • frissített_idő

Az első a rekord létrehozásának dátumát és időpontját, a második pedig az utolsó módosítás dátumát és időpontját tárolja. És minden entitásosztálynak vannak mezői:


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

A Hibernate minden feladatot képes ellenőrizni, ha az adatbázisban lévő objektumok két megjegyzéssel @CreationTimestampés @UpdateTimestamp.

Példa:

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

Az ezekkel a megjegyzésekkel jelölt oszlopok mindig az objektum létrehozásának és utolsó módosításának pontos idejét tárolják.

5.2 @PrePersist annotáció

Ha bonyolultabb szkriptekre van szüksége egy objektum idejének szabályozásához, akkor a Hibernate erre az esetre is rendelkezik megjegyzésekkel. Megjelölhetik az osztálymetódusokat, és a Hibernate ezeket a metódusokat hívja meg, amikor elmenti az objektumot az adatbázisba. Összesen 7 ilyen megjegyzés van:

@PrePersist Az objektum adatbázisba mentése előtt hívják meg. (SQL INSERT)
@PostPersist Az objektum adatbázisba mentése után azonnal meghívódik. (SQL INSERT)
@PreRemove Meghívás az adatbázisban lévő objektum törlése előtt.
@PostRemove Egy objektum adatbázisból való törlése után hívódik meg.
@PreUpdate Az adatbázisban lévő objektum frissítése (SQL UPDATE) előtt meghívva.
@PostUpdate Az adatbázisban lévő objektum frissítése (SQL UPDATE) után hívják meg.
@postload Meghívás az objektum adatbázisból való betöltése után.

Írjunk egy példát, ahol megmondjuk egy osztálynak az objektumok létrehozásának és frissítésének pontos idejét:

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

Ha a Hibernate először menti el az objektumot, akkor meghívja a -val jelölt metódust @PrePersist. Ha frissít egy meglévő objektumot az adatbázisban, akkor meghívja a megjegyzéssel jelölt metódust @PreUpdate.

5.3 EntityListeners hozzáadása

Ha valóban szüksége van rá, akkor elkülönítheti a Hibernate által meghívott metódusokat attól az objektumtól, amelyen meghívja őket. A JPA specifikáció lehetővé teszi olyan figyelőosztályok deklarálását, amelyek bizonyos időpontokban meghívásra kerülnek az entitás objektumok feldolgozása során.

Ha sok hasonló entitás objektummal rendelkezik, akkor áthelyezhet néhányat az alaposztályba, és hozzáadhat egy figyelőt, amely szabályozza a viselkedésüket. Példa:


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


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

Ezután a BaseEntity osztályhoz létrehozhat egy speciális figyelő osztályt:


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

És összekapcsolhatja a User osztályt és a figyelőjét néhány megjegyzés segítségével:


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