5.1 Masa perubahan data

Apabila anda menyimpan pelbagai rekod dalam pangkalan data selama bertahun-tahun, dua soalan sering timbul:

  • Bilakah entri ini ditambahkan pada pangkalan data?
  • Bilakah kali terakhir entri ini ditukar?

Ini adalah tugas yang kerap sehingga dua lajur ditambahkan pada hampir setiap jadual dalam pangkalan data:

  • masa_dicipta
  • masa_kemas kini

Yang pertama menyimpan tarikh dan masa rekod dibuat, dan yang kedua menyimpan tarikh dan masa ia terakhir diubah suai. Dan setiap kelas Entiti mempunyai medan:


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

Hibernate boleh melakukan semua kerja mengawal apabila objek dalam pangkalan data dikemas kini dengan dua anotasi @CreationTimestampdan @UpdateTimestamp.

Contoh:

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

Lajur yang ditandakan dengan anotasi ini akan sentiasa menyimpan masa yang betul apabila objek itu dibuat dan bila kali terakhir ia diubah suai.

5.2 anotasi @PrePersist

Jika anda memerlukan beberapa skrip yang lebih kompleks untuk mengawal masa sesuatu objek, maka Hibernate mempunyai anotasi untuk kes ini juga. Mereka boleh menandakan kaedah kelas, dan Hibernate akan memanggil kaedah ini apabila ia menyimpan objek ke pangkalan data. Terdapat 7 anotasi sedemikian secara keseluruhan:

@PrePersist Dipanggil sebelum objek disimpan ke pangkalan data. (Sisipan SQL)
@PostPersist Dipanggil serta-merta selepas objek disimpan ke pangkalan data. (Sisipan SQL)
@PreRemove Dipanggil sebelum memadam objek dalam pangkalan data.
@PostRemove Dipanggil selepas objek telah dipadamkan daripada pangkalan data.
@PreUpdate Dipanggil sebelum mengemas kini (SQL UPDATE) objek dalam pangkalan data.
@PostUpdate Dipanggil selepas kemas kini (SQL UPDATE) objek dalam pangkalan data.
@PostLoad Dipanggil selepas objek telah dimuatkan daripada pangkalan data.

Mari tulis contoh di mana kita memberitahu kelas masa yang betul untuk mencipta dan mengemas kini objeknya:

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

Jika Hibernate menyimpan objek buat kali pertama, maka ia akan memanggil kaedah beranotasi dengan @PrePersist. Jika ia mengemas kini objek sedia ada dalam pangkalan data, ia akan memanggil kaedah yang ditandakan dengan anotasi @PreUpdate.

5.3 Menambah EntityListeners kami

Jika anda benar-benar perlu, maka anda boleh memisahkan kaedah yang dipanggil Hibernate daripada objek yang ia memanggilnya. Spesifikasi JPA membolehkan anda mengisytiharkan kelas pendengar yang akan dipanggil pada masa tertentu apabila memproses objek Entiti.

Jika anda mempunyai banyak objek Entiti yang serupa, maka anda boleh memindahkan sebahagian daripadanya ke dalam kelas asas dan menambah Pendengar yang akan mengawal tingkah laku mereka. Contoh:


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


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

Kemudian untuk kelas BaseEntity, anda boleh membuat kelas pendengar khas:


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

Dan anda boleh menyambungkan kelas Pengguna dan pendengarnya menggunakan beberapa anotasi:


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