为了账号安全,请及时绑定邮箱和手机立即绑定

更新 Hibernate 中每一行的时间戳

更新 Hibernate 中每一行的时间戳

缥缈止盈 2021-10-28 17:28:11
我的 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    private void onUpdate(){        this.lastEditDate = new Date();    }@更新时间戳@UpdateTimestamp    @Temporal(TemporalType.TIMESTAMP)    private Date lastEditDate;但是我得到的是,当我更新一行时,所有行的时间戳都会更新,因此表中的所有时间戳始终相同。我在这里做错了什么?
查看完整描述

2 回答

?
莫回无

TA贡献1865条经验 获得超7个赞

有很多方法可以实现这一目标。


@实体监听器

你可以有一个@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

您也可以使用@PrePersist和@PreUpdateJPA 注释:


@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

}

并将Auditembeddable添加到实体中,如下所示:


@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

}

特定于 Hibernate 的@CreationTimestamp和@UpdateTimestamp

@CreationTimestamp

@Column(name = "created_on")

private Date createdOn;


@Column(name = "updated_on")

@UpdateTimestamp

private Date updatedOn;

就是这样!


现在,与您的评论有关:


但是我得到的是,当我更新一行时,所有行的时间戳都会更新,因此表中的所有时间戳始终相同。我在这里做错了什么?


时间戳只会为被修改的实体更新,而不是为所有行更新。当只有一行被修改时,更新所有行的时间戳没有任何意义。否则,为什么要在行本身上放置该列?


如果您想要上次修改时间戳,只需运行如下查询:


SELECT MAX(updated_on)

FROM tags


查看完整回答
反对 回复 2021-10-28
  • 2 回答
  • 0 关注
  • 152 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信