我的Postgres数据库中有一个带有时间戳列的表。我希望每次更新一行时自动插入它。我写了一个数据库触发器:
CREATE FUNCTION update_last_edit_date() RETURNS trigger AS $update_last_edit_date$
BEGIN
NEW.last_edit_date := localtimestamp(0);
RETURN NEW;
END;
$update_last_edit_date$ LANGUAGE plpgsql;
CREATE TRIGGER update_last_edit_date BEFORE UPDATE ON employee
FOR EACH ROW
WHEN (OLD.* IS DISTINCT FROM NEW.*)
EXECUTE PROCEDURE update_last_edit_date();
哪个可以正常工作,但是我想知道是否有更简单的方法可以使用jpa / hibernate注释来做到这一点。我尝试了这些不同的选择:
@Preupdate
@PreUpdate
private void onUpdate(){
this.lastEditDate = new Date();
}
@UpdateTimestamp
@UpdateTimestamp
@Temporal(TemporalType.TIMESTAMP)
private Date lastEditDate;
但是我得到的是,当我更新一行时,所有行的时间戳都会更新,因此表中的所有时间戳总是相同的。我在这里做什么错了?
答案 0 :(得分:2)
有很多方法可以实现这一目标。
如this article中所述,您可以使用@Embeddable
来存储审核属性:
@Embeddable
public class Audit {
@Column(name = "created_on")
private LocalDateTime createdOn;
@Column(name = "updated_on")
private LocalDateTime updatedOn;
//Getters and setters omitted for brevity
}
要求使用EntityListener
的形式如下:
public class AuditListener {
@PrePersist
public void setCreatedOn(Auditable auditable) {
Audit audit = auditable.getAudit();
if(audit == null) {
audit = new Audit();
auditable.setAudit(audit);
}
audit.setCreatedOn(LocalDateTime.now());
}
@PreUpdate
public void setUpdatedOn(Auditable auditable) {
Audit audit = auditable.getAudit();
audit.setUpdatedOn(LocalDateTime.now());
}
}
您的实体将必须实现Audit
接口:
public interface Auditable {
Audit getAudit();
void setAudit(Audit audit);
}
实体将如下所示:
@Entity(name = "Tag")
@Table(name = "tag")
@EntityListeners(AuditListener.class)
public class Tag implements Auditable {
@Id
private String name;
@Embedded
private Audit audit;
//Getters and setters omitted for brevity
}
这是一个非常优雅的解决方案,因为它从主要实体映射中提取了审计逻辑。
@PrePersist
和@PreUpdate
正如我在this article中所述,您还可以使用@PrePersist
和@PreUpdate
JPA批注:
@Embeddable
public class Audit {
@Column(name = "created_on")
private LocalDateTime createdOn;
@Column(name = "updated_on")
private LocalDateTime updatedOn;
@PrePersist
public void prePersist() {
createdOn = LocalDateTime.now();
}
@PreUpdate
public void preUpdate() {
updatedOn = LocalDateTime.now();
}
//Getters and setters omitted for brevity
}
,然后将Audit
嵌入到实体中,如下所示:
@Entity(name = "Tag")
@Table(name = "tag")
public class Tag {
@Id
private String name;
@Embedded
private Audit audit = new Audit();
//Getters and setters omitted for brevity
}
@CreationTimestamp
和@UpdateTimestamp
@CreationTimestamp
@Column(name = "created_on")
private Date createdOn;
@Column(name = "updated_on")
@UpdateTimestamp
private Date updatedOn;
就是这样!
现在,与您的评论有关:
但是我得到的是,当我更新一行时,所有行的时间戳都会更新,因此表中的所有时间戳总是相同的。我在这里做什么错了?
只会为要修改的实体更新时间戳,而不是为所有行更新时间戳。仅修改一行时,更新所有行的时间戳没有任何意义。否则,为什么要在行本身上添加该列?
如果您想要最后一次修改的时间戳,只需运行如下查询:
SELECT MAX(updated_on)
FROM tags
答案 1 :(得分:1)
如果您使用的是spring-data,则可以通过审核功能执行此操作。结帐@EnableJpa审核或阅读本文https://www.baeldung.com/database-auditing-jpa