1. Які типи стовпців бази даних слід використовувати
Ваше перше питання:
Які типи даних ви б використовували в базі даних (припускаючи MySQL, можливо, в іншому часовому поясі, ніж JVM)? Чи будуть відомі типи даних часовим поясом?
У MySQL TIMESTAMP
тип стовпця робить перехід від локального часового поясу драйвера JDBC до часового поясу бази даних, але він може зберігати лише часові позначки до '2038-01-19 03:14:07.999999
, тому це не найкращий вибір для майбутнього.
Тож краще скористайтеся DATETIME
замість цього, яке не має цього верхнього обмеження. Однак DATETIME
не відомо про часовий пояс. Тому з цієї причини найкраще використовувати UTC на стороні бази даних та використовувати hibernate.jdbc.time_zone
властивість Hibernate.
Детальніше про hibernate.jdbc.time_zone
налаштування див. У цій статті .
2. Який тип властивості сутності ви повинні використовувати
Ваше друге питання:
Які типи даних ви б використовували на Java (дата, календар, довгий, ...)?
З боку Java ви можете використовувати Java 8 LocalDateTime
. Ви також можете використовувати спадщину Date
, але типи дати / часу Java 8 є кращими, оскільки вони незмінні, і не здійснюйте переміщення часового поясу на локальний часовий пояс під час реєстрації.
Щоб отримати докладнішу інформацію про типи дати / часу Java 8, підтримуваних Hibernate, перегляньте цю статтю .
Тепер ми також можемо відповісти на це питання:
Які анотації ви б використали для картографування (наприклад @Temporal
)?
Якщо ви використовуєте LocalDateTime
або java.sql.Timestamp
для відображення властивості об'єкта часової позначки, вам це не потрібно використовувати, @Temporal
оскільки HIbernate вже знає, що це властивість потрібно зберігати як JDBC Timestamp.
Тільки якщо ви користуєтесь java.util.Date
, вам потрібно вказати @Temporal
примітку, наприклад:
@Temporal(TemporalType.TIMESTAMP)
@Column(name = "created_on")
private Date createdOn;
Але, набагато краще, якщо відобразити його так:
@Column(name = "created_on")
private LocalDateTime createdOn;
Як генерувати значення стовпців аудиту
Ваше третє питання:
Кого б ви відповідали за встановлення часових позначок - база даних, рамка ORM (сплячий режим) або програміст програми?
Які анотації ви б використали для картографування (наприклад, @Temporal)?
Є багато способів досягти цієї мети. Ви можете дозволити цьому зробити базу даних ..
Для create_on
стовпця ви можете використовувати DEFAULT
обмеження DDL, наприклад:
ALTER TABLE post
ADD CONSTRAINT created_on_default
DEFAULT CURRENT_TIMESTAMP() FOR created_on;
Для updated_on
стовпця ви можете використовувати тригер DB для встановлення значення стовпця CURRENT_TIMESTAMP()
щоразу, коли заданий рядок буде змінено.
Або використовуйте JPA або Hibernate, щоб встановити їх.
Припустимо, у вас є такі таблиці баз даних:
І в кожній таблиці є стовпці типу:
created_by
created_on
updated_by
updated_on
Використання сплячого режиму @CreationTimestamp
та @UpdateTimestamp
приміток
Hibernate пропонує @CreationTimestamp
та @UpdateTimestamp
примітки та примітки, які можна використовувати для відображення стовпців created_on
та updated_on
стовпців.
Ви можете використовувати @MappedSuperclass
для визначення базового класу, який буде розширений усіма сутностями:
@MappedSuperclass
public class BaseEntity {
@Id
@GeneratedValue
private Long id;
@Column(name = "created_on")
@CreationTimestamp
private LocalDateTime createdOn;
@Column(name = "created_by")
private String createdBy;
@Column(name = "updated_on")
@UpdateTimestamp
private LocalDateTime updatedOn;
@Column(name = "updated_by")
private String updatedBy;
//Getters and setters omitted for brevity
}
І всі суб'єкти господарювання поширять BaseEntity
, як це:
@Entity(name = "Post")
@Table(name = "post")
public class Post extend BaseEntity {
private String title;
@OneToMany(
mappedBy = "post",
cascade = CascadeType.ALL,
orphanRemoval = true
)
private List<PostComment> comments = new ArrayList<>();
@OneToOne(
mappedBy = "post",
cascade = CascadeType.ALL,
orphanRemoval = true,
fetch = FetchType.LAZY
)
private PostDetails details;
@ManyToMany
@JoinTable(
name = "post_tag",
joinColumns = @JoinColumn(
name = "post_id"
),
inverseJoinColumns = @JoinColumn(
name = "tag_id"
)
)
private List<Tag> tags = new ArrayList<>();
//Getters and setters omitted for brevity
}
Для отримання більш докладної інформації про використання @MappedSuperclass
, перевірити цю статтю .
Тим НЕ менше, навіть якщо createdOn
і updateOn
властивості встановлюються з допомогою Hibernate-специфічних @CreationTimestamp
і @UpdateTimestamp
анотації, то createdBy
і updatedBy
вимагають реєстрації зворотного виклику програми, як показано з допомогою наступного розчину JPA.
Використання JPA @EntityListeners
Ви можете інкапсулювати властивості аудиту в Embeddable:
@Embeddable
public class Audit {
@Column(name = "created_on")
private LocalDateTime createdOn;
@Column(name = "created_by")
private String createdBy;
@Column(name = "updated_on")
private LocalDateTime updatedOn;
@Column(name = "updated_by")
private String updatedBy;
//Getters and setters omitted for brevity
}
І створіть AuditListener
для встановлення властивостей аудиту:
public class AuditListener {
@PrePersist
public void setCreatedOn(Auditable auditable) {
Audit audit = auditable.getAudit();
if(audit == null) {
audit = new Audit();
auditable.setAudit(audit);
}
audit.setCreatedOn(LocalDateTime.now());
audit.setCreatedBy(LoggedUser.get());
}
@PreUpdate
public void setUpdatedOn(Auditable auditable) {
Audit audit = auditable.getAudit();
audit.setUpdatedOn(LocalDateTime.now());
audit.setUpdatedBy(LoggedUser.get());
}
}
Для реєстрації AuditListener
ви можете використовувати @EntityListeners
анотацію JPA:
@Entity(name = "Post")
@Table(name = "post")
@EntityListeners(AuditListener.class)
public class Post implements Auditable {
@Id
private Long id;
@Embedded
private Audit audit;
private String title;
@OneToMany(
mappedBy = "post",
cascade = CascadeType.ALL,
orphanRemoval = true
)
private List<PostComment> comments = new ArrayList<>();
@OneToOne(
mappedBy = "post",
cascade = CascadeType.ALL,
orphanRemoval = true,
fetch = FetchType.LAZY
)
private PostDetails details;
@ManyToMany
@JoinTable(
name = "post_tag",
joinColumns = @JoinColumn(
name = "post_id"
),
inverseJoinColumns = @JoinColumn(
name = "tag_id"
)
)
private List<Tag> tags = new ArrayList<>();
//Getters and setters omitted for brevity
}
Щоб отримати докладніші відомості про реалізацію властивостей аудиту в JPA @EntityListener
, перегляньте цю статтю .