对于某个Hibernate实体,我们需要存储它的创建时间和最后一次更新时间。你会怎么设计呢?

您将在数据库中使用什么数据类型(假设MySQL,可能位于与JVM不同的时区)?数据类型是否支持时区? 你会在Java中使用什么数据类型(日期,日历,长,…)? 您会让谁负责设置时间戳——数据库、ORM框架(Hibernate)还是应用程序程序员? 你会为映射使用什么注释(例如@Temporal)?

我不仅在寻找一个可行的解决方案,而且在寻找一个安全、设计良好的解决方案。


当前回答

我们也遇到过类似的情况。我们使用的是Mysql 5.7。

CREATE TABLE my_table (
        ...
      updated_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
    );

这对我们很管用。

其他回答

如果你正在使用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注释,并将事件代码放在外部类中。

我们也遇到过类似的情况。我们使用的是Mysql 5.7。

CREATE TABLE my_table (
        ...
      updated_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
    );

这对我们很管用。

作为JAVA中的数据类型,我强烈建议使用JAVA .util. date。在使用Calendar时,我遇到了非常糟糕的时区问题。请看这个帖子。

对于设置时间戳,我建议使用AOP方法,或者您可以简单地在表上使用触发器(实际上,这是我发现使用触发器唯一可以接受的事情)。

使用Olivier的解决方案,在更新语句期间,您可能会遇到:

com.mysql.jdbc.exceptions.jdbc4。MySQLIntegrityConstraintViolationException:列“created”不能为空

要解决这个问题,在"created"属性的@Column注释中添加updatable=false:

@Temporal(TemporalType.TIMESTAMP)
@Column(name = "created", nullable = false, updatable=false)
private Date created;

您还可以使用拦截器来设置这些值

创建一个名为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;
    }
}

并将其注册到会话工厂