How to persist creation and update timestamps with Hibernate

By Thorben Janssen

Mapping

Storing the creation timestamp or the timestamp of the last update is a common requirement for modern applications. It sounds like a simple requirement, but for a huge application, you don’t want to set a new update timestamp in every use case that changes the entity.

You need a simple, fail-safe solution that automatically updates the timestamp for each and every change. As so often, there are multiple ways to achieve that:

  • You can use a database update trigger that performs the change on a database level. Most DBAs will suggest this approach because it’s easy to implement on a database level. But Hibernate needs to perform an additional query to retrieve the generated values from the database.
  • You can use an entity lifecycle event to update the timestamp attribute of the entity before Hibernate performs the update.
  • You can use an additional framework, like Hibernate Envers, to write an audit log and get the update timestamp from there.
  • You can use the Hibernate-specific @CreationTimestamp and @UpdateTimestamp annotations and let Hibernate trigger the required updates.

It’s obvious that the last option is the easiest one to implement if you can use Hibernate-specific features. So let’s have a more detailed look at it.

@CreationTimestamp and @UpdateTimestamp

Hibernate’s @CreationTimestamp and @UpdateTimestamp annotations make it easy to track the timestamp of the creation and last update of an entity.

When a new entity gets persisted, Hibernate gets the current timestamp from the VM and sets it as the value of the attribute annotated with @CreationTimestamp. After that, Hibernate will not change the value of this attribute.

The value of the attribute annotated with @UpdateTimestamp gets changed in a similar way with every SQL Update statement. Hibernate gets the current timestamp from the VM and sets it as the update timestamp on the SQL Update statement.

Supported attribute types

You can use the @CreationTimestamp and @UpdateTimestamp with the following attribute types:

  • java.time.LocalDate (since Hibernate 5.2.3)
  • java.time.LocalDateTime (since Hibernate 5.2.3)
  • java.util.Date
  • java.util.Calendar
  • java.sql.Date
  • java.sql.Time
  • java.sql.Timestamp

Example

Let’s have a look at an example entity that uses the 2 annotations to store the timestamp of its creation and last update.

As you can see in the following code snippet, I just added the @CreationTimestamp annotation to the createDateTime attribute and the @UpdateTimestamp annotation to the updateDateTime attribute.

@Entity
public class MyEntity {

	@Id
	@GeneratedValue
	private Long id;

	private String value;

	@CreationTimestamp
	private LocalDateTime createDateTime;

	@UpdateTimestamp
	private LocalDateTime updateDateTime;

	…

}

When you persist a new MyEntity, Hibernate will get the current time from the VM and store it as the creation and update timestamp. As you can see in the log output, Hibernate gets a new timestamp for each attribute. The creation and update timestamp will therefore not be the same even if the entity was never updated.

MyEntity e = new MyEntity();
em.persist(e);
15:35:49,785 DEBUG SQL:92 – insert into MyEntity (createDateTime, updateDateTime, value, id) values (?, ?, ?, ?)
15:35:49,789 TRACE BasicBinder:65 – binding parameter [1] as [TIMESTAMP] – [2016-10-10T15:35:49.772]
15:35:49,791 TRACE BasicBinder:65 – binding parameter [2] as [TIMESTAMP] – [2016-10-10T15:35:49.776]
15:35:49,792 TRACE BasicBinder:53 – binding parameter [3] as [VARCHAR] – [null]
15:35:49,793 TRACE BasicBinder:65 – binding parameter [4] as [BIGINT] – [1]

Hibernate will change the update timestamp with each SQL Update statement and keep the creation timestamp unchanged. But you might be surprised, when you see the generated SQL Update statement. It also updates the creation timestamp and sets it to its initial value.

e = em.find(MyEntity.class, 1L);
e.setValue(“A Value”);
15:35:49,804 DEBUG SQL:92 – update MyEntity set createDateTime=?, updateDateTime=?, value=? where id=?
15:35:49,804 TRACE BasicBinder:65 – binding parameter [1] as [TIMESTAMP] – [2016-10-10T15:35:49.772]
15:35:49,805 TRACE BasicBinder:65 – binding parameter [2] as [TIMESTAMP] – [2016-10-10T15:35:49.804]
15:35:49,805 TRACE BasicBinder:65 – binding parameter [3] as [VARCHAR] – [A Value]
15:35:49,805 TRACE BasicBinder:65 – binding parameter [4] as [BIGINT] – [1]

Summary

Tracking the creation and last update timestamp of a database record is a common requirement. As you’ve seen, Hibernate’s @CreationTimestamp and @UpdateTimestamp annotations make it easy to implement. You just have to add an annotation to an entity attribute and Hibernate will take care of the necessary updates.


Tags

Mapping


About the author

Thorben is an independent consultant, international speaker, and trainer specialized in solving Java persistence problems with JPA and Hibernate.
He is also the author of Amazon’s bestselling book Hibernate Tips - More than 70 solutions to common Hibernate problems.

Books and Courses

Coaching and Consulting

Leave a Repl​​​​​y

Your email address will not be published. Required fields are marked

This site uses Akismet to reduce spam. Learn how your comment data is processed.

  1. need to use @Column(updatable = false) on insertTimeStamp column. otherwise JPA updates it as null.
    I am Using SpringBoot2 with JPA

    1. I can’t reproduce the problem. Hibernate doesn’t change the insertTimeStamp when I update the entity.
      Which SpringBoot and Hibernate version do you use?

  2. I had conflict when use @CreationTimestamp and @UpdateTimestamp with @Version annotation.
    I got a optimistic locking. I think this not looks at the version column on update. Do you have too ?
    … when a have some time free i’ll try fix it.

    Grats Thorben!

    1. I tested it with multiple Hibernate 5.x releases and it worked fine with all of them.
      Which Hibernate version do you use?

  3. During first time insertion, update timestamp will be null right?. As it is applicable only during update.
    Is there a feature like first time it should be populated with create timestamp, and on every update it should get updated. Can you please brief about the behaviour.

    1. The update timestamp is never null. It gets set in the SQL INSERT statement but it doesn’t contain the same value as the insert timestamp.

    1. Hibernate uses the timezone configured for your JVM. So, if you want to use a specific one, just make sure that it’s used by your JVM.

    1. That depends… Which annotations do you want to apply?

      You can’t apply the @CreationTimestamp and @UpdateTimestamp annotations to the same field. In that case, you should only use the @UpdateTimestamp annotation because it also gets set when you persist the entity.

  4. Thorben, great article!

    very simple solution to persist update time from VM but if you want to persist time from DB what is the best approach?
    I know that @PrePersist and @PreUpdate can be used for this but I want to avoid additional query.
    On DB level we can do something like this: update xxxTable set time_modified = current_timestamp, column1 = ?, … where id = ?. Is there anything in Hibernate to achieve this?

    Thanks
    Milan

    1. Thanks Milan.

      You could use a database trigger to set the time_modified field on each insert and update statement. If you annotate the corresponding entity attribute with @Generated, Hibernate makes sure to get the generated value from the database and to update the value of the entity attribute. But that, of course, requires an additional query. You can learn more about it at Hibernate Tips: Map generated values

      Regards,
      Thorben

  5. Im trying to use the annotations with Hibernate 5.2.10 Final but im still getting the error: Unsupported Property type for generator annotation @CreationTimestamp
    I’m using it with LocalDateTime type.

    1. Are you sure that you’re using Hibernate 5.2.10.Final at runtime?
      This looks like an error message that you would get with an older version.
      I tested it with Hibernate 5.2.10 and it works fine.

    1. Unfortunately, you can’t parameterize it. Hibernate uses the JVM to get the current time. So, you would need to control that …

    1. Hi Betto,

      it only persists the timestamps so it’s not a real audit solution. But if you don’t need to persist any additional information (who changed what), this is the easiest solution I know.

      1. Hi Thorben,
        Great article. Was looking for something like this! Actually I was looking for something which would use database timestamp rather than Java VM timestamps because it happens sometimes that db time and application server time are out of sync. But even this trick is good enough. But I’m using Spring Data JPA with Hibernate Implementation. I have avoided using hibernate annotations and kept it purely jpa in my classes. Just want to ask if it is alright to use hibernate annotation or use some jpa alternative? And do you have any suggestions if want to save using DB time rather than Application Time. One simplest and worst way I can think of is calling the db to get it’s current time use it to set in the java code but I guess it’s not optimal solution.

        1. Hi Mohammed,

          Do you plan to replace Hibernate with a different JPA implementation?
          In my experience, that almost never happens. If you don’t expect to switch to a different JPA implementation, you can use Hibernate annotations in your mapping.

          If you don’t want to use any Hibernate-specific annotations, you could use an EntityListener or lifecycle callback instead.

          Regards,
          Thorben

{"email":"Email address invalid","url":"Website address invalid","required":"Required field missing"}