Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to store only specific timestamp columns in UTC in hibernate

In my Mysql DB, I have some columns which need to be stored in UTC using hibernate. I can't force my JVM to store all timestamp column in UTC as I have other columns for different time zones. I have found two solutions

1) To configure hostname as jdbc:mysql://hostname/databaseName?useTimezone=true&serverTimezone=UTC 

2)  private static final TimeZone UTC = TimeZone.getTimeZone("UTC");

But both the solution is for forcing timezone in UTC for all the columns where as my requirement is for specific columns.

    @CreatedDate
    @Temporal(TemporalType.TIMESTAMP)
    @Column(nullable = false,updatable = false, name="created_at")
    private Date createdAt;
like image 866
Himanshu Avatar asked Mar 11 '18 07:03

Himanshu


1 Answers

You can do that manually in your code, for specifically 1 column. Basically, the idea is to update the date to the desired date just before updating in the DB.

For this, You will need to assign a listener in the Hibernate's EventListenerRegistry. The following class will apply a CreateOrUpdateDateListener listener (created by you) just before it performs the save operation.

@Component
public class HibernateEventWiring {

    @Autowired
    @Qualifier(value = "your_sessionFactory")           //Your session factory
    private LocalSessionFactoryBean sessionFactory;

    @Autowired
    private CreateOrUpdateDateListener listener;

    @PostConstruct
    public void registerListeners() {
        EventListenerRegistry registry = ((SessionFactoryImpl) sessionFactory.getObject()).getServiceRegistry().getService(
                EventListenerRegistry.class);
        registry.getEventListenerGroup(EventType.SAVE_UPDATE).appendListener(listener);
    }
}

The following class extends DefaultSaveOrUpdateEventListener and adds your custom code of updating the timestamp to what you want. And, we have used it's object as a listener in EventListenerRegistry

@Component
public class CreateOrUpdateDateListener extends DefaultSaveOrUpdateEventListener {

    @Override
    public void onSaveOrUpdate(SaveOrUpdateEvent event) {
        if (event.getObject() instanceof CreateUpdateTimestamp) {
            CreateUpdateTimestamp record = (CreateUpdateTimestamp) event.getObject();
            record.setUpdatedTimestamp(LocalDateTime.now(Clock.systemUTC()));
        }
        super.onSaveOrUpdate(event);
    }
}

public interface CreateUpdateTimestamp {
    public void setCreatedTimestamp(LocalDateTime date);
    public void setUpdatedTimestamp(LocalDateTime date);
}

Following is the entity class. This class will implement CreateUpdateTimestamp so that we can use this class via CreateUpdateTimestamp's ref in CreateOrUpdateDateListener.

@Entity
@Table(name = "transactions")
public class Transaction implements CreateUpdateTimestamp{

    private LocalDateTime updatedTimestamp;

    @Column(name = "updated_timestamp", insertable = true, updatable = true)
    public LocalDateTime getUpdatedTimestamp() {
        return updatedTimestamp;
    }
    public void setUpdatedTimestamp(LocalDateTime updatedTimestamp) {
        this.updatedTimestamp = updatedTimestamp;
    }
}
like image 146
Pankaj Singhal Avatar answered Sep 27 '22 22:09

Pankaj Singhal