为Hibernate中的每一行更新时间戳

时间:2018-10-06 11:22:26

标签: java postgresql hibernate jpa timestamp

我的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;

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

2 个答案:

答案 0 :(得分:2)

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

@EntityListener

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