对于某个Hibernate实体,我们需要存储它的创建时间和最后一次更新时间。你会怎么设计呢?
您将在数据库中使用什么数据类型(假设MySQL,可能位于与JVM不同的时区)?数据类型是否支持时区? 你会在Java中使用什么数据类型(日期,日历,长,…)? 您会让谁负责设置时间戳——数据库、ORM框架(Hibernate)还是应用程序程序员? 你会为映射使用什么注释(例如@Temporal)?
我不仅在寻找一个可行的解决方案,而且在寻找一个安全、设计良好的解决方案。
对于某个Hibernate实体,我们需要存储它的创建时间和最后一次更新时间。你会怎么设计呢?
您将在数据库中使用什么数据类型(假设MySQL,可能位于与JVM不同的时区)?数据类型是否支持时区? 你会在Java中使用什么数据类型(日期,日历,长,…)? 您会让谁负责设置时间戳——数据库、ORM框架(Hibernate)还是应用程序程序员? 你会为映射使用什么注释(例如@Temporal)?
我不仅在寻找一个可行的解决方案,而且在寻找一个安全、设计良好的解决方案。
当前回答
如果你正在使用JPA注释,你可以使用@PrePersist和@PreUpdate事件钩子来做到这一点:
@Entity
@Table(name = "entities")
public class Entity {
...
private Date created;
private Date updated;
@PrePersist
protected void onCreate() {
created = new Date();
}
@PreUpdate
protected void onUpdate() {
updated = new Date();
}
}
或者您可以在类上使用@EntityListener注释,并将事件代码放在外部类中。
其他回答
如果你正在使用JPA注释,你可以使用@PrePersist和@PreUpdate事件钩子来做到这一点:
@Entity
@Table(name = "entities")
public class Entity {
...
private Date created;
private Date updated;
@PrePersist
protected void onCreate() {
created = new Date();
}
@PreUpdate
protected void onUpdate() {
updated = new Date();
}
}
或者您可以在类上使用@EntityListener注释,并将事件代码放在外部类中。
您还可以使用拦截器来设置这些值
创建一个名为TimeStamped的接口,由实体实现
public interface TimeStamped {
public Date getCreatedDate();
public void setCreatedDate(Date createdDate);
public Date getLastUpdated();
public void setLastUpdated(Date lastUpdatedDate);
}
定义拦截器
public class TimeStampInterceptor extends EmptyInterceptor {
public boolean onFlushDirty(Object entity, Serializable id, Object[] currentState,
Object[] previousState, String[] propertyNames, Type[] types) {
if (entity instanceof TimeStamped) {
int indexOf = ArrayUtils.indexOf(propertyNames, "lastUpdated");
currentState[indexOf] = new Date();
return true;
}
return false;
}
public boolean onSave(Object entity, Serializable id, Object[] state,
String[] propertyNames, Type[] types) {
if (entity instanceof TimeStamped) {
int indexOf = ArrayUtils.indexOf(propertyNames, "createdDate");
state[indexOf] = new Date();
return true;
}
return false;
}
}
并将其注册到会话工厂
我们也遇到过类似的情况。我们使用的是Mysql 5.7。
CREATE TABLE my_table (
...
updated_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
);
这对我们很管用。
下面的代码对我有用。
package com.my.backend.models;
import java.util.Date;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.MappedSuperclass;
import com.fasterxml.jackson.annotation.JsonIgnore;
import org.hibernate.annotations.ColumnDefault;
import org.hibernate.annotations.CreationTimestamp;
import org.hibernate.annotations.UpdateTimestamp;
import lombok.Getter;
import lombok.Setter;
@MappedSuperclass
@Getter @Setter
public class BaseEntity {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
protected Integer id;
@CreationTimestamp
@ColumnDefault("CURRENT_TIMESTAMP")
protected Date createdAt;
@UpdateTimestamp
@ColumnDefault("CURRENT_TIMESTAMP")
protected Date updatedAt;
}
只是强调一下:java.util. calendar不是用于时间戳的。date是指时间上的某一刻,不受时区等区域性事物的影响。大多数数据库以这种方式存储数据(即使它们看起来不是这样;这通常是客户端软件中的时区设置;数据是好的)