usar ejemplo como java hibernate timestamp

java - ejemplo - Marca de tiempo de creación y última hora de actualización con Hibernate y MySQL



hibernate java netbeans mysql (13)

Para una determinada entidad de Hibernate, tenemos el requisito de almacenar su tiempo de creación y la última vez que se actualizó. ¿Cómo diseñarías esto?

  • ¿Qué tipos de datos usaría en la base de datos (asumiendo MySQL, posiblemente en una zona horaria diferente a la JVM)? ¿Los tipos de datos tendrán en cuenta la zona horaria?

  • ¿Qué tipos de datos utilizarías en Java ( Date , Calendar , long , ...)?

  • ¿A quién responsabilizaría de establecer las marcas de tiempo: la base de datos, el marco de trabajo de ORM (Hibernate) o el programador de aplicaciones?

  • ¿Qué anotaciones usaría para el mapeo (por ejemplo, @Temporal )?

No solo busco una solución que funcione, sino una solución segura y bien diseñada.



Como tipo de datos en JAVA, recomiendo usar java.util.Date. Me encontré con problemas de zona horaria bastante desagradables al usar el calendario. Ver este Thread

Para establecer las marcas de tiempo, recomendaría usar un enfoque AOP o simplemente podría utilizar Desencadenadores en la tabla (en realidad, esto es lo único que encuentro aceptable para el uso de desencadenadores).


Con la solución de Olivier, durante las declaraciones de actualización puede encontrarse con:

com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolationException: la columna ''creada'' no puede ser nula

Para resolver esto, agregue updatable = false a la anotación @Column del atributo "creado":

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


En caso de que esté utilizando la API de sesión, las devoluciones de llamada PrePersist y PreUpdate no funcionarán de acuerdo con esta answer .

Estoy utilizando el método persist () de Hibernate Session en mi código, por lo que la única manera de hacer que esto funcione es con el código que se encuentra a continuación y siguiendo esta publicación del blog (también publicada en la 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; } }


Gracias a todos los que ayudaron. Después de investigar un poco (soy el tipo que hizo la pregunta), esto es lo que encontré que tiene más sentido:

  • Tipo de columna de la base de datos: el número de milisegundos desde 1970 respecto a la zona horaria, representado como decimal(20) porque 2 ^ 64 tiene 20 dígitos y el espacio en disco es barato; seamos sencillos Además, no DEFAULT CURRENT_TIMESTAMP , ni activadores. No quiero magia en el DB.

  • Tipo de campo de Java: long . La marca de tiempo de Unix está bien soportada en varias librerías, long no tiene problemas con Y2038, la aritmética de marca de tiempo es rápida y fácil (principalmente operador < y operador + , suponiendo que no hay días / meses / años involucrados en los cálculos). Y, lo que es más importante, tanto los primitivos long s como los java.lang.Long s son inmutables, pasados ​​por valor de manera efectiva, a diferencia de java.util.Date s; Me foo.getLastUpdate().setTime(System.currentTimeMillis()) encontrar algo como foo.getLastUpdate().setTime(System.currentTimeMillis()) al depurar el código de otra persona.

  • El marco ORM debe ser responsable de completar los datos automáticamente.

  • Todavía no he probado esto, pero solo mirando los documentos asumo que @Temporal hará el trabajo; No estoy seguro de si podría usar @Version para este propósito. @PrePersist y @PreUpdate son buenas alternativas para controlar eso manualmente. Agregar eso al supertipo de capa (clase base común) para todas las entidades, es una buena idea siempre y cuando realmente desee un sello de tiempo para todas sus entidades.


Podría considerar almacenar la hora como DateTime y en UTC. Normalmente uso DateTime en lugar de la marca de tiempo porque MySql convierte las fechas a UTC y vuelve a la hora local cuando almacena y recupera los datos. Prefiero mantener ese tipo de lógica en un solo lugar (capa empresarial). Estoy seguro de que hay otras situaciones en las que es preferible usar Timestamp.


Si está utilizando las anotaciones JPA, puede usar los enganches de eventos @PrePersist y @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(); } }

o puede usar la anotación @EntityListener en la clase y colocar el código de evento en una clase externa.


Solo para reforzar: java.util.Calender no es para Timestamps . java.util.Date es por un momento en el tiempo, agnóstico de cosas regionales como zonas horarias. La mayoría de las bases de datos almacenan cosas de esta manera (incluso si parecen no hacerlo; esta es generalmente una configuración de zona horaria en el software cliente; la información es buena)


Solo puedes usar @CreationTimestamp y @UpdateTimestamp :

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


También puede utilizar un interceptor para establecer los valores

Cree una interfaz llamada TimeStamped que implementan sus entidades

public interface TimeStamped { public Date getCreatedDate(); public void setCreatedDate(Date createdDate); public Date getLastUpdated(); public void setLastUpdated(Date lastUpdatedDate); }

Define el interceptor

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

Y registralo en la sesion de fábrica.


Tomando los recursos en esta publicación junto con la información tomada de izquierda a derecha de diferentes fuentes, vine con esta elegante solución, cree la siguiente clase abstracta

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

y haz que todas tus entidades lo amplíen, por ejemplo:

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


Tuvimos una situación similar. Estábamos utilizando Mysql 5.7.

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

Esto funcionó para nosotros.


Un buen enfoque es tener una clase base común para todas sus entidades. En esta clase base, puede tener su propiedad de identificación si es comúnmente nombrada en todas sus entidades (un diseño común), su creación y las propiedades de la fecha de la última actualización.

Para la fecha de creación, simplemente mantenga una propiedad java.util.Date . Asegúrese de inicializarlo siempre con la nueva Fecha () .

Para el último campo de actualización, puede usar una propiedad de marca de tiempo, debe asignarla con @Version. Con esta anotación, la propiedad se actualizará automáticamente por Hibernate. Tenga en cuenta que Hibernate también aplicará un bloqueo optimista (es algo bueno).