当前位置:  开发笔记 > 编程语言 > 正文

使用Hibernate和MySQL创建时间戳和上次更新时间戳

如何解决《使用Hibernate和MySQL创建时间戳和上次更新时间戳》经验,为你挑选了7个好方法。

对于某个Hibernate实体,我们需要存储其创建时间和上次更新时间.你会怎么设计这个?

您将在数据库中使用哪些数据类型(假设MySQL,可能在与JVM不同的时区)?数据类型是时区感知的吗?

你会在Java中使用什么数据类型(Date,Calendar,long,...)?

您将负责设置时间戳 - 数据库,ORM框架(Hibernate)或应用程序员?

您将使用哪些注释进行映射(例如@Temporal)?

我不只是在寻找一个可行的解决方案,而是一个安全且设计良好的解决方案.



1> 小智..:

如果您使用的是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的当前Hibernate中,可以使用"@CreationTimestamp"和"@UpdateTimestamp"
良好的灵魂,但在使用Hibernate Session时无法工作.
在J2SE中没有任何问题,因为@PrePersist和@PerUpdate是JPA注释.
@Kumar - 如果您使用普通的Hibernate会话(而不是JPA),您可以尝试使用hibernate事件监听器,尽管与JPA注释相比,它不是非常优雅和紧凑.

2> idmitriev..:

你可以使用@CreationTimestamp@UpdateTimestamp:

@CreationTimestamp
@Temporal(TemporalType.TIMESTAMP)
@Column(name = "create_date")
private Date createDate;

@UpdateTimestamp
@Temporal(TemporalType.TIMESTAMP)
@Column(name = "modify_date")
private Date modifyDate;


谢谢兄弟这么小的东西需要更新时间戳.我不知道.你救了我的一天.
当我更新对象并持久化时,bd丢失了create_date ...为什么?

3> Olivier Refa..:

利用这篇文章中的资源以及从不同来源左右传递的信息,我带来了这个优雅的解决方案,创建了以下抽象类

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 {
...
}


这是好的,直到您想要向实体添加_different_独占行为(并且您不能扩展多个基类).afaik没有基类获得相同效果的唯一方法是尽管aspectj itd或事件监听器看到@kieren dixon回答
我会使用MySQL触发器执行此操作,以便即使完整实体未保存或被任何外部应用程序或手动查询修改,它仍将更新这些字段.
你可以给我任何工作的例子,因为我遇到异常`not-null属性引用一个null或瞬态值:package.path.ClassName.created`

4> Kieren Dixon..:

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

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

并在会话工厂注册



5> endriju..:

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

com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolationException:列'created'不能为null

要解决此问题,请将updatable = false添加到"created"属性的@Column注释中:

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



6> ngn..:

谢谢所有帮助过的人.在自己做了一些研究之后(我就是问过这个问题的人),这是我发现最有意义的事情:

数据库列类型:自1970年以来与时区无关的毫秒数表示为decimal(20)因为2 ^ 64有20位数且磁盘空间便宜; 让我们直截了当.此外,我将既不使用也不使用DEFAULT CURRENT_TIMESTAMP触发器.我想在DB中没有魔力.

Java字段类型:long.Unix时间戳在各种库中得到很好的支持,long没有Y2038问题,时间戳算法快速而简单(主要是运算符<和运算符+,假设计算中没有涉及天/月/年).并且,最重要的是,原始longs和java.lang.Longs都是不可变的 -有效地通过值传递 - 与java.util.Dates 不同; foo.getLastUpdate().setTime(System.currentTimeMillis())在调试其他人的代码时,我真的很生气.

ORM框架应负责自动填写数据.

我还没有测试过这个,但只看了我认为@Temporal可以完成工作的文档; 不确定我是否可以@Version用于此目的. @PrePersist并且@PreUpdate是手动控制的好方法.将其添加到所有实体的图层超类型(公共基类),这是一个可爱的想法,前提是您确实需要为所有实体设置时间戳.


没关系.Hibernate无论如何都需要setter(或者它会尝试直接通过反射访问该字段).我在谈论追逐谁从我们的应用程序代码修改时间戳的困难.使用getter可以做到这一点很棘手.

7> vicch..:

如果您使用的是Session API,则根据此答案,PrePersist和PreUpdate回调将不起作用.

我在我的代码中使用Hibernate Session的persist()方法,所以我能够完成这项工作的唯一方法是使用下面的代码并关注此博客文章(也在答案中发布).

@MappedSuperclass
public abstract class AbstractTimestampEntity {

    @Temporal(TemporalType.TIMESTAMP)
    @Column(name = "created")
    private Date created=new Date();

    @Temporal(TemporalType.TIMESTAMP)
    @Column(name = "updated")
    @Version
    private Date updated;

    public Date getCreated() {
        return created;
    }

    public void setCreated(Date created) {
        this.created = created;
    }

    public Date getUpdated() {
        return updated;
    }

    public void setUpdated(Date updated) {
        this.updated = updated;
    }
}

推荐阅读
雯颜哥_135
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有