java - Timestamp de criação e registro de data e hora da última atualização com o Hibernate e o MySQL




7 Answers

Se você estiver usando as anotações JPA, poderá usar os ganchos de evento @PreUpdate e @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();
  }
}

ou você pode usar a anotação @EntityListener na classe e colocar o código do evento em uma classe externa.

Para uma certa entidade do Hibernate, temos um requisito para armazenar seu tempo de criação e a última vez que foi atualizado. Como você projetaria isso?

  • Quais tipos de dados você usaria no banco de dados (assumindo o MySQL, possivelmente em um fuso horário diferente do que a JVM)? Os tipos de dados terão reconhecimento de fuso horário?

  • Quais tipos de dados você usaria em Java ( Date , Calendar , long , ...)?

  • Quem você faria responsável por definir os timestamps - o banco de dados, o framework ORM (Hibernate) ou o programador de aplicativos?

  • Quais anotações você usaria para o mapeamento (por exemplo, @Temporal )?

Não estou apenas procurando por uma solução funcional, mas por uma solução segura e bem projetada.




Tomando os recursos neste post junto com informações tiradas da esquerda e direita de diferentes fontes, eu vim com essa solução elegante, criei a seguinte classe abstrata

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();
    }
}

e ter todas as suas entidades estendidas, por exemplo:

@Entity
@Table(name = "campaign")
public class Campaign extends AbstractTimestampEntity implements Serializable {
...
}



Obrigado a todos que ajudaram. Depois de fazer uma pesquisa eu mesmo (eu sou o cara que fez a pergunta), aqui está o que eu encontrei para fazer mais sentido:

  • Tipo de coluna de banco de dados: o número de milissegundos agnóstico de fuso horário desde 1970 representado como decimal(20) porque 2 ^ 64 tem 20 dígitos e o espaço em disco é barato; vamos ser direto. Além disso, não usarei nem o DEFAULT CURRENT_TIMESTAMP nem os triggers. Eu não quero mágica no DB.

  • Tipo de campo Java: long . O timestamp do Unix é bem suportado em várias libs, não tem problemas com o Y2038, a aritmética do timestamp é rápida e fácil (principalmente operator < e operator + , assumindo que nenhum dia / mês / ano esteja envolvido nos cálculos). E, mais importante, tanto os primitivos s long quanto os java.lang.Long s são imutáveis ​​- efetivamente passados ​​por valor - ao contrário de java.util.Date s; Eu ficaria muito chateado para encontrar algo como foo.getLastUpdate().setTime(System.currentTimeMillis()) ao depurar o código de outra pessoa.

  • O framework ORM deve ser responsável por preencher os dados automaticamente.

  • Eu não testei isso ainda, mas apenas olhando para os documentos eu assumo que o @Temporal fará o trabalho; Não tenho certeza se devo usar o @Version para esse propósito. @PrePersist e @PreUpdate são boas alternativas para controlar isso manualmente. Adicionar isso ao supertipo de camada (classe base comum) para todas as entidades é uma idéia interessante, desde que você realmente deseje o registro de data e hora para todas as suas entidades.




Caso você esteja usando a Session API, os callbacks PrePersist e PreUpdate não funcionarão de acordo com esta answer .

Eu estou usando o método persist () do Hibernate Session no meu código, então a única maneira que eu poderia fazer este trabalho foi com o código abaixo e seguindo este post (também postado na answer ).

@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;
    }
}



Uma boa abordagem é ter uma classe base comum para todas as suas entidades. Nesta classe base, você pode ter sua propriedade id se ela for comumente nomeada em todas as suas propriedades de entidades (um design comum), sua criação e a última data de atualização.

Para a data de criação, você simplesmente mantém uma propriedade java.util.Date . Certifique-se de sempre inicializá-lo com a nova data () .

Para o último campo de atualização, você pode usar uma propriedade de carimbo de data / hora, você precisa mapeá-lo com @Version. Com esta anotação, a propriedade será atualizada automaticamente pelo Hibernate. Esteja ciente de que o Hibernate também aplicará bloqueio otimista (é uma coisa boa).




Como tipo de dados no JAVA, eu recomendo fortemente usar o java.util.Date. Eu encontrei problemas de fuso horário bastante desagradáveis ​​ao usar o Google Agenda. Veja este Thread .

Para definir os timestamps, eu recomendaria usar uma abordagem AOP ou você poderia simplesmente usar Triggers na tabela (na verdade, essa é a única coisa que eu acho que o uso de triggers é aceitável).




Nós tivemos uma situação semelhante. Nós estávamos usando o Mysql 5.7.

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

Isso funcionou para nós.




Related