3

I'm facing strange issue last modified date is not getting updated automatically. I'm using Postgresql Version 12.3 and Springboot 2.2.4.RELEASE Here's my Entity Class

@Entity
@Table(name = "users")
@org.hibernate.annotations.Entity(
        dynamicUpdate = true
)
@Data
public class Users {


    @Id
    @GeneratedValue(generator = "UUID")
    @GenericGenerator(
            name = "UUID",
            strategy = "org.hibernate.id.UUIDGenerator"
    )
    @Column(updatable = false, nullable = false)
        private String userId;

        private String userName;

        private String userEmail;

        private String userPhoneNumber;

        @CreationTimestamp
        @Column(updatable = false)
        @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+05:30")
        private Timestamp createdOn;

        @UpdateTimestamp
        @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+05:30")
        private Timestamp lastUpdatedOn;

}

Database Records:

            createdon        |      lastupdatedon
 2020-08-27 07:43:37.994 | 2020-08-27 07:43:37.994
 2020-08-07 07:49:22.797 | 2020-08-07 07:49:22.797
 2020-08-12 13:38:43.503 | 2020-08-12 13:38:43.503

You can see both createdOn and lastUpdatedOn are same. Even though the records updated frequently last modified date is not getting updated.

I'm saving record with jpa repository ex:

 usersRepository.save(user); 
5
  • And how are you updating those records. Commented Nov 18, 2020 at 14:45
  • using jpa methods like, usersRepository.save(user); Commented Nov 18, 2020 at 14:46
  • One thing have you tried without the hibernate specific dynamicUpdate? Just wondering. Also are you not updating something with a query somewhere (as that bypasses the listeners). Commented Nov 18, 2020 at 15:04
  • @M.Deinum I tried updating the record directly with CLI (psql), even from theer also lastUpdatedOn not changing. Commented Nov 18, 2020 at 15:58
  • Ofcourse it won't change if you directly execute SQL. It is a feature of Spring Data JPA, so if you bypass that, it won't do anything. Commented Nov 18, 2020 at 16:06

2 Answers 2

2

Can you try using PrePersist & PreUpdate annotation instead of CreationTimestamp & UpdateTimestampas to have more control on the entity and apply below-

@Entity
@Table(name = "users")
@org.hibernate.annotations.Entity(
        dynamicUpdate = true
)
@Data
public class Users {


    @Id
    @GeneratedValue(generator = "UUID")
    @GenericGenerator(
            name = "UUID",
            strategy = "org.hibernate.id.UUIDGenerator"
    )
    @Column(updatable = false, nullable = false)
    private String userId;

    private String userName;

    private String userEmail;

    private String userPhoneNumber;

    @Column(updatable = false)
    private Timestamp createdOn;

    @Column
    private Timestamp lastUpdatedOn;

    @PrePersist
    public void onInsert() {
      createdOn = Timestamp.from(ZonedDateTime.now(ZoneId.of("Asia/Kolkata")).toInstant());
      lastUpdatedOn = createdOn;
    }

    @PreUpdate
    public void onUpdate() {
      lastUpdatedOn = Timestamp.from(ZonedDateTime.now(ZoneId.of("Asia/Kolkata")).toInstant());
     }
}
Sign up to request clarification or add additional context in comments.

1 Comment

Under the hood, this is what eventually will be used, although through a listener.
1

Are you calling the save method within a transaction, by chance?

The timestamps are populated when written to the DB, so you won't see their values until after the transaction has been committed.

When I ran into this issue, I had code that looked like this:

@Transactional
public Response createFooBusinessLogic(Foo foo) {
    var createdEntity = fooRepository.save(foo);
    return someMethodUsingCreatedTime(createdEntity);
}

There are two solutions:

  1. If the dates are required by another entity in the DB transaction, you can use saveAndFlush instead of save. This forces a write to the DB, returning back your created and modified dates.
  2. Otherwise, refactor the save call into another method and annotate that method with @Transactional.

I went with option (2), which looked like this:

public Response createFooBusinessLogic(Foo foo) {
    var createdEntity = facade.saveFoo(foo);
    return someMethodUsingCreatedTime(createdEntity);
}

// In Facade.java
@Transactional
public Foo saveFoo(Foo foo) {
    return fooRepository.save(foo);
}

Note that for the transaction annotation to work, the call must not be self-invoking (ie. must be called on another class) and the method must be public.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.