对于某个Hibernate实体,我们需要存储它的创建时间和最后一次更新时间。你会怎么设计呢?
您将在数据库中使用什么数据类型(假设MySQL,可能位于与JVM不同的时区)?数据类型是否支持时区? 你会在Java中使用什么数据类型(日期,日历,长,…)? 您会让谁负责设置时间戳——数据库、ORM框架(Hibernate)还是应用程序程序员? 你会为映射使用什么注释(例如@Temporal)?
我不仅在寻找一个可行的解决方案,而且在寻找一个安全、设计良好的解决方案。
对于某个Hibernate实体,我们需要存储它的创建时间和最后一次更新时间。你会怎么设计呢?
您将在数据库中使用什么数据类型(假设MySQL,可能位于与JVM不同的时区)?数据类型是否支持时区? 你会在Java中使用什么数据类型(日期,日历,长,…)? 您会让谁负责设置时间戳——数据库、ORM框架(Hibernate)还是应用程序程序员? 你会为映射使用什么注释(例如@Temporal)?
我不仅在寻找一个可行的解决方案,而且在寻找一个安全、设计良好的解决方案。
当前回答
我认为在Java代码中不这样做更整洁,你可以简单地在MySql表定义中设置列的默认值。
其他回答
谢谢所有帮助过我的人。在我自己做了一些研究之后(我是问这个问题的人),以下是我发现最有意义的:
Database column type: the timezone-agnostic number of milliseconds since 1970 represented as decimal(20) because 2^64 has 20 digits and disk space is cheap; let's be straightforward. Also, I will use neither DEFAULT CURRENT_TIMESTAMP, nor triggers. I want no magic in the DB. Java field type: long. The Unix timestamp is well supported across various libs, long has no Y2038 problems, timestamp arithmetic is fast and easy (mainly operator < and operator +, assuming no days/months/years are involved in the calculations). And, most importantly, both primitive longs and java.lang.Longs are immutable—effectively passed by value—unlike java.util.Dates; I'd be really pissed off to find something like foo.getLastUpdate().setTime(System.currentTimeMillis()) when debugging somebody else's code. The ORM framework should be responsible for filling in the data automatically. I haven't tested this yet, but only looking at the docs I assume that @Temporal will do the job; not sure about whether I might use @Version for this purpose. @PrePersist and @PreUpdate are good alternatives to control that manually. Adding that to the layer supertype (common base class) for all entities, is a cute idea provided that you really want timestamping for all of your entities.
我们也遇到过类似的情况。我们使用的是Mysql 5.7。
CREATE TABLE my_table (
...
updated_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
);
这对我们很管用。
利用本文中的资源以及来自不同来源的左右信息,我提出了这个优雅的解决方案,创建以下抽象类
import java.util.Date;
import javax.persistence.Column;
import javax.persistence.MappedSuperclass;
import javax.persistence.PrePersist;
import javax.persistence.PreUpdate;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
@MappedSuperclass
public abstract class AbstractTimestampEntity {
@Temporal(TemporalType.TIMESTAMP)
@Column(name = "created", nullable = false)
private Date created;
@Temporal(TemporalType.TIMESTAMP)
@Column(name = "updated", nullable = false)
private Date updated;
@PrePersist
protected void onCreate() {
updated = created = new Date();
}
@PreUpdate
protected void onUpdate() {
updated = new Date();
}
}
并让你的所有实体扩展它,例如:
@Entity
@Table(name = "campaign")
public class Campaign extends AbstractTimestampEntity implements Serializable {
...
}
您可以考虑将时间存储为DateTime,并且使用UTC。我通常使用DateTime而不是Timestamp,因为MySql在存储和检索数据时将日期转换为UTC和本地时间。我宁愿把所有这些逻辑都放在一个地方(业务层)。我相信在其他情况下使用时间戳更可取。
如果你正在使用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注释,并将事件代码放在外部类中。