5.1 Время изменения данных

Когда ты хранишь различные записи в базе данных долгие годы, то очень часто возникают два вопроса:

  • Когда данная запись была добавлена в базу данных?
  • Когда данная запись менялась последний раз?

Это настолько частые задачи, что практически в каждую таблицу в базе данных добавляют две колонки:

  • created_time
  • updated_time

В первой хранится дата и время создания записи, а во второй – дата и время ее последнего изменения. И в каждом Entity-классе есть поля:


@Entity
@Table(name = "entities")	
public class Entity {
  ...
 
  @Column(name="created_time")
  private Date created;
 
  @Column(name="updated_time")
  private Date updated;
}

Hibernate может взять на себя всю работу по контролю за временем обновления объектов в базе с помощью двух аннотаций @CreationTimestamp и @UpdateTimestamp.

Пример:


@Entity
@Table(name = "entities")	
public class Entity {
  ...
 
	@CreationTimestamp
    @Temporal(TemporalType.TIMESTAMP)
    @Column(name = "create_date")
    private Date createDate;
 
	@UpdateTimestamp
    @Temporal(TemporalType.TIMESTAMP)
    @Column(name = "modify_date")
	private Date modifyDate;
}

В колонках, помеченных данными аннотациями, всегда будет храниться правильное время создания объекта и его последнего изменения.

5.2 Аннотация @PrePersist

Если тебе нужны какие-то более сложные сценарии для контроля времени объекта, то у Hibernate есть аннотации и на этот случай. Ими можно пометить методы класса, и Hibernate вызовет эти методы, когда будет сохранять объект в базу. Всего таких аннотаций 7:

@PrePersist Вызывается перед сохранением объекта в базу. (SQL INSERT)
@PostPersist Вызывается сразу после сохранения объекта в базу. (SQL INSERT)
@PreRemove Вызывается перед удалением объекта в базе.
@PostRemove Вызывается после удаления объекта в базе.
@PreUpdate Вызывается перед обновлением (SQL UPDATE) объекта в базе.
@PostUpdate Вызывается после обновления (SQL UPDATE) объекта в базе.
@PostLoad Вызывается после того, как объект был загружен из базы.

Давай напишем пример, где мы прописываем классу правильное время создания и обновления его объектов:


@Entity
@Table(name = "entities")	
public class Entity {
  ...
 
  @Column(name="created_time")
  private Date created;
 
  @Column(name="updated_time")
  private Date updated;
 
  @PrePersist
  protected void onCreate() {
    created = new Date();
  }
 
  @PreUpdate
  protected void onUpdate() {
  updated = new Date();
  }
}

Если Hibernate сохраняет объект в первый раз, то он вызовет метод, помеченный аннотацией @PrePersist. Если обновляет в базе существующий объект, то вызовет метод, помеченный аннотацией @PreUpdate.

5.3 Добавляем свои EntityListeners

Если тебе очень надо, то ты можешь отделить методы, которые вызывает Hibernate, от объекта, у которого он их вызывает. Спецификация JPA позволяет тебе объявить listener-классы, которые будут вызываться в определенные моменты обработки Entity-объектов.

Если у тебя много похожих Entity-объектов, то ты можешь вынести их часть в базовый класс и добавить Listener, который бы управлял их поведением. Пример:


@MappedSuperclass
public abstract class BaseEntity {
 
    private Timestamp createdOn;
 
    private Timestamp updatedOn;
 
}


@Entity
public class User extends BaseEntity {
 
     @Id
     private Long id;
 
     private String name;
}

Тогда для класса BaseEntity можно создать специальный listener-класс:


public class TimeEntityListener {
 
    public void onPersist(Object entity) {
    	if (entity instanceof BaseEntity) {
        	BaseEntity baseEntity = (BaseEntity) entity;
        	baseEntity.createdOn = now();
    	}
    }
 
    public void onUpdate(Object entity) {
    	if (entity instanceof BaseEntity) {
        	BaseEntity baseEntity = (BaseEntity) entity;
        	baseEntity.updatedOn = now();
    	}
    }
 
    private Timestamp now() {
    	return Timestamp.from(LocalDateTime.now().toInstant(ZoneOffset.UTC)   );
    }
}

И связать класс User и его listener можно с помощью парочки аннотаций:


@Entity
@EntityListeners(class= TimeEntityListener.class)
public class User extends BaseEntity {
 
     @Id
     private Long id;
 
     private String name;
}

undefined
1
Задача
Модуль 4. Работа с БД, 12 уровень, 4 лекция
Недоступна
Время создания и изменения данных
Если ранее не подключал зависимости, то подключи их. Для этого используй Alt + Ctrl + Shift + S (в Идее), вкладка Libraries. Зависимости можно скачать здесь: https://javarush.com/downloads/ide/javarush/hibernate.zip Архив распакуй, и каждую зависимость добавь к модулю. Эта часть задания не проверяется, но если ее не выполнить, ты не сможешь локально выполнять код.