【问题标题】:Update timestamp for each row in Hibernate更新 Hibernate 中每一行的时间戳
【发布时间】:2019-03-11 17:22:01
【问题描述】:

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

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

【问题讨论】:

  • 任何 JPA 注释将只适用于一行……一个对象……根据定义。如果您更新了所有行,那么这特定于您数据库中的其他内容,并且超出了 JPA 的范围。 JPA 日志告诉您 IT 正在做什么。

标签: java postgresql hibernate jpa timestamp


【解决方案1】:

如果您使用的是 spring-data,那么您可以通过审计功能执行此操作。结帐@EnableJpaAuditing 或阅读这篇文章https://www.baeldung.com/database-auditing-jpa

【讨论】:

    【解决方案2】:

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

    @EntityListener

    您可以使用@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@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
    }
    

    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
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2010-09-18
      • 2010-11-05
      • 1970-01-01
      • 2021-05-20
      • 1970-01-01
      • 2016-10-07
      相关资源
      最近更新 更多