Update timestamp for each row in Hibernate

Matt :

I have a table in my Postgres database which has a timestamp column. I would like to have it be automatically inserted every time I update a row. I wrote a database trigger:

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();

Which works fine but I was wondering if there was an easier way to do this with jpa/hibernate annotations. I tried these different options:

@Preupdate

@PreUpdate
    private void onUpdate(){
        this.lastEditDate = new Date();
    }

@UpdateTimestamp

@UpdateTimestamp
    @Temporal(TemporalType.TIMESTAMP)
    private Date lastEditDate;

But what I get is that when I update one row, the timestamps for all of the rows updated, so all of the timestamps in the table are always the same. What am I doing wrong here?

Vlad Mihalcea :

There are many ways to achieve this goal.

@EntityListener

As explained in this article, you can have an @Embeddable to store the audit properties:

@Embeddable
public class Audit {

    @Column(name = "created_on")
    private LocalDateTime createdOn;

    @Column(name = "updated_on")
    private LocalDateTime updatedOn;

    //Getters and setters omitted for brevity
}

Which requires an EntityListener that looks as follows:

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());
    }
}

You entities will have to implement the Audit interface:

public interface Auditable {

    Audit getAudit();

    void setAudit(Audit audit);
}

And the entities will look like this:

@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
}

This is a very elegant solution since it extracts the audit logic from the main entity mapping.

@PrePersist and @PreUpdate

As I explained in this article, you can use the @PrePersist and @PreUpdate JPA annotations as well:

@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
}

and add the Audit embeddable to the entity like this:

@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-specific @CreationTimestamp and @UpdateTimestamp

@CreationTimestamp
@Column(name = "created_on")
private Date createdOn;

@Column(name = "updated_on")
@UpdateTimestamp
private Date updatedOn;

That's it!

Now, related to your comment:

But what I get is that when I update one row, the timestamps for all of the rows updated, so all of the timestamps in the table are always the same. What am I doing wrong here?

The timestamp will only be updated for the entity that gets modified, not for all rows. It does not make any sense to update the timestamp of all rows when only a single row gets modified. Otherwise, why would you have that column on the row itself?

If you want the last modification timestamp, just run a query like this:

SELECT MAX(updated_on)
FROM tags

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=99643&siteId=1