5.1 Thời điểm thay đổi dữ liệu
Khi bạn lưu trữ các bản ghi khác nhau trong cơ sở dữ liệu trong nhiều năm, hai câu hỏi thường nảy sinh:
- Mục nhập này được thêm vào cơ sở dữ liệu khi nào?
- Mục nhập này được thay đổi lần cuối khi nào?
Đây là những nhiệm vụ thường xuyên đến mức hai cột được thêm vào hầu hết mọi bảng trong cơ sở dữ liệu:
- created_time
- updated_time
Cái đầu tiên lưu trữ ngày và giờ bản ghi được tạo và cái thứ hai lưu trữ ngày và giờ nó được sửa đổi lần cuối. Và mỗi lớp Thực thể có các trường:
@Entity
@Table(name = "entities")
public class Entity {
...
@Column(name="created_time")
private Date created;
@Column(name="updated_time")
private Date updated;
}
Hibernate có thể thực hiện tất cả công việc kiểm soát khi các đối tượng trong cơ sở dữ liệu được cập nhật với hai chú thích @CreationTimestamp
và tệp @UpdateTimestamp
.
Ví dụ:
@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;
}
Các cột được đánh dấu bằng các chú thích này sẽ luôn lưu trữ thời gian chính xác khi đối tượng được tạo và khi nó được sửa đổi lần cuối.
5.2 Chú thích @PrePersist
Nếu bạn cần một số script phức tạp hơn để kiểm soát thời gian của một đối tượng thì Hibernate cũng có các chú thích cho trường hợp này. Chúng có thể đánh dấu các phương thức của lớp, và Hibernate sẽ gọi các phương thức này khi nó lưu đối tượng vào cơ sở dữ liệu. Tổng cộng có 7 chú thích như vậy:
@PrePersist | Được gọi trước khi đối tượng được lưu vào cơ sở dữ liệu. (CHÈN SQL) |
@PostPersist | Được gọi ngay sau khi đối tượng được lưu vào cơ sở dữ liệu. (CHÈN SQL) |
@PreRemove | Được gọi trước khi xóa một đối tượng trong cơ sở dữ liệu. |
@PostRemove | Được gọi sau khi một đối tượng đã bị xóa khỏi cơ sở dữ liệu. |
@PreUpdate | Được gọi trước khi cập nhật (SQL UPDATE) một đối tượng trong cơ sở dữ liệu. |
@PostUpdate | Được gọi sau một bản cập nhật (SQL UPDATE) của một đối tượng trong cơ sở dữ liệu. |
@postload | Được gọi sau khi đối tượng đã được tải từ cơ sở dữ liệu. |
Hãy viết một ví dụ trong đó chúng tôi thông báo cho một lớp thời điểm chính xác để tạo và cập nhật các đối tượng của nó:
@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();
}
}
Nếu Hibernate lưu đối tượng lần đầu tiên, thì nó sẽ gọi phương thức được chú thích bằng @PrePersist
. Nếu nó cập nhật một đối tượng hiện có trong cơ sở dữ liệu, nó sẽ gọi phương thức được đánh dấu bằng chú thích @PreUpdate
.
5.3 Thêm EntityListeners của chúng tôi
Nếu thực sự cần, thì bạn có thể tách các phương thức mà Hibernate gọi ra khỏi đối tượng mà nó gọi chúng. Đặc tả JPA cho phép bạn khai báo các lớp trình nghe sẽ được gọi vào những thời điểm nhất định khi xử lý các đối tượng Thực thể.
Nếu bạn có nhiều đối tượng Thực thể tương tự, thì bạn có thể di chuyển một số trong số chúng vào lớp cơ sở và thêm Trình xử lý sẽ kiểm soát hành vi của chúng. Ví dụ:
@MappedSuperclass
public abstract class BaseEntity {
private Timestamp createdOn;
private Timestamp updatedOn;
}
@Entity
public class User extends BaseEntity {
@Id
private Long id;
private String name;
}
Sau đó, đối với lớp BaseEntity, bạn có thể tạo một lớp người nghe đặc biệt:
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) );
}
}
Và bạn có thể kết nối lớp Người dùng và trình nghe của nó bằng một vài chú thích:
@Entity
@EntityListeners(class= TimeEntityListener.class)
public class User extends BaseEntity {
@Id
private Long id;
private String name;
}