5.1 Czas zmiany danych

Gdy przechowujesz różne rekordy w bazie danych przez wiele lat, często pojawiają się dwa pytania:

  • Kiedy ten wpis został dodany do bazy danych?
  • Kiedy ten wpis był ostatnio zmieniany?

Są to tak częste zadania, że ​​prawie do każdej tabeli w bazie danych dodawane są dwie kolumny:

  • utworzony_czas
  • zaktualizowany_czas

Pierwsza przechowuje datę i godzinę utworzenia rekordu, a druga przechowuje datę i godzinę ostatniej modyfikacji. A każda klasa Entity ma pola:


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

Hibernate może wykonać całą pracę polegającą na kontrolowaniu, kiedy obiekty w bazie danych są aktualizowane za pomocą dwóch adnotacji @CreationTimestampi @UpdateTimestamp.

Przykład:

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

Kolumny oznaczone tymi adnotacjami zawsze będą przechowywać poprawny czas utworzenia obiektu i jego ostatniej modyfikacji.

5.2 Adnotacja @PrePersist

Jeśli potrzebujesz bardziej złożonych skryptów do kontrolowania czasu obiektu, Hibernate ma również adnotacje dla tego przypadku. Mogą oznaczać metody klas, a Hibernate wywoła te metody, gdy zapisze obiekt w bazie danych. W sumie jest 7 takich adnotacji:

@PrePersist Wywoływana przed zapisaniem obiektu w bazie danych. (WSTAW SQL)
@PostPersist Wywoływana natychmiast po zapisaniu obiektu w bazie danych. (WSTAW SQL)
@PreRemove Wywoływana przed usunięciem obiektu z bazy danych.
@PostUsuń Wywoływana po usunięciu obiektu z bazy danych.
@PreUpdate Wywoływana przed aktualizacją (SQL UPDATE) obiektu w bazie danych.
@PostAktualizacja Wywoływana po aktualizacji (SQL UPDATE) obiektu w bazie danych.
@PostLoad Wywoływana po załadowaniu obiektu z bazy danych.

Napiszmy przykład, w którym podajemy klasie właściwy czas tworzenia i aktualizowania jej obiektów:

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

Jeśli Hibernate zapisze obiekt po raz pierwszy, wywoła metodę z adnotacją @PrePersist. Jeśli zaktualizuje istniejący obiekt w bazie danych, wywoła metodę oznaczoną adnotacją @PreUpdate.

5.3 Dodawanie naszych EntityListeners

Jeśli naprawdę potrzebujesz, możesz oddzielić metody wywoływane przez Hibernate od obiektu, na którym je wywołuje. Specyfikacja JPA umożliwia zadeklarowanie klas nasłuchiwania, które będą wywoływane w określonych momentach podczas przetwarzania obiektów Entity.

Jeśli masz wiele podobnych obiektów Entity, możesz przenieść niektóre z nich do klasy bazowej i dodać Listener, który kontrolowałby ich zachowanie. Przykład:


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


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

Następnie dla klasy BaseEntity możesz utworzyć specjalną klasę detektora:


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

I możesz połączyć klasę User i jej słuchacza za pomocą kilku adnotacji:


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