0

Since I can't make MySQL to update a column with ON UPDATE, I'm thinking of using Hibernate's interceptors, to update an updated table each time the row is updated.

My only concern is, how much of a performance penalty does it imply, compared to the ideal case of having MySQL updating it?

Community
  • 1
  • 1
user384729
  • 403
  • 1
  • 7
  • 16
  • Turn on the mysql's general log to capture what Hibernate is sending to MySQL. – Rick James Feb 06 '16 at 00:57
  • For what its worth.. the bigger issue is not performance. Rather the fact that only one access method is applying the timestamp. So for example if you do an UPDATE from the database client or another client accessing the same database, that update timestamp won't be recorded. Which might be a real problem for certain use-cases (like compliance) – Steve Ebersole Feb 09 '16 at 20:47
  • @SteveEbersole: Hadn't really thought of that, thanks. I guess it that case I would use both approaches at the same time. – user384729 Feb 10 '16 at 09:03

1 Answers1

1

There's no significant performance penalty and you don't need an interceptor either.

I created an example on GitHub for this.

You need to create a JPA callback listener:

public class UpdatableListener {

    @PrePersist
    @PreUpdate
    private void setCurrentTimestamp(Object entity) {
        if(entity instanceof Updatable) {
            Updatable updatable = (Updatable) entity;
            updatable.setTimestamp(new Date());
        }
    }

}

which uses an interface that's defined like this:

public interface Updatable {

    void setTimestamp(Date timestamp);

    Date getTimestamp();
}

You can then define a base class for all your entities:

@MappedSuperclass
@EntityListeners(UpdatableListener.class)
public class BaseEntity implements Updatable {

    @Column(name = "update_timestamp")
    private Date timestamp;

    @Override
    public void setTimestamp(Date timestamp) {
        this.timestamp = timestamp;
    }

    @Override
    public Date getTimestamp() {
        return timestamp;
    }
}

And then simply have your entities extend it:

@Entity(name = "Post")
@Table(name = "post")
public class Post extends BaseEntity {
    ...  
}

@Entity(name = "PostComment")
@Table(name = "post_comment")
public static class PostComment extends BaseEntity {
    ...  
}

When you modify these entities:

doInJPA(entityManager -> {
    Post post = entityManager.find(Post.class, 1L);
    post.setTitle("Post");
    for(PostComment comment : post.getComments()) {
        comment.setReview("Review");
    }
});

Hibernate will take care of setting the timestamp column:

UPDATE  post
SET     update_timestamp = '2016-02-06 17:03:26.759' ,
        title = 'Post'
WHERE   id = 1
UPDATE  post_comment
SET     update_timestamp = '2016-02-06 17:03:26.76' ,
        post_id = 1 ,
        review = 'Review'
WHERE   id = 1
UPDATE  post_comment
SET     update_timestamp = '2016-02-06 17:03:26.76' ,
        post_id = 1 ,
        review = 'Review'
WHERE   id = 2
Vlad Mihalcea
  • 142,745
  • 71
  • 566
  • 911
  • Thanks. I mentioned interceptors because I read that integrating listeners with Spring became tricky. http://stackoverflow.com/questions/8616146/eventlisteners-using-hibernate-4-0-with-spring-3-1-0-release – user384729 Feb 08 '16 at 08:48
  • But that issue is closed. – Vlad Mihalcea Feb 08 '16 at 11:59