¿Establecer una columna de marca de tiempo JPA para ser generada por la base de datos?


En mi base de datos SQL Server 2000, tengo una columna de marca de tiempo (en función no en tipo de datos) de tipo DATETIME llamada lastTouched establecida en getdate() como su valor/enlace predeterminado.

Estoy usando las clases de entidad JPA generadas por Netbeans 6.5, y tengo esto en mi código

@Basic(optional = false)
@Column(name = "LastTouched")
@Temporal(TemporalType.TIMESTAMP)
private Date lastTouched;

Sin embargo, cuando intento poner el objeto en la base de datos obtengo,

javax.persistence.PersistenceException: org.hibernate.PropertyValueException: not-null property references a null or transient value: com.generic.Stuff.lastTouched

He intentado configurar el @Basic a (optional = true), pero eso arroja una excepción diciendo que la base de datos no permite null valores para el TIMESTAMP columna, que no lo hace por diseño.

ERROR JDBCExceptionReporter - Cannot insert the value NULL into column 'LastTouched', table 'DatabaseName.dbo.Stuff'; column does not allow nulls. INSERT fails.

Anteriormente conseguí que esto funcionara en Hibernación pura, pero tengo sentido cambiado a JPA y no tengo idea de cómo decirle que se supone que esta columna se genera en el lado de la base de datos. Tenga en cuenta que todavía estoy usando Hibernate como mi capa de persistencia JPA.

Author: Vladimir Vagaytsev, 2009-05-01

5 answers

Solucioné el problema cambiando el código a

@Basic(optional = false)
@Column(name = "LastTouched", insertable = false, updatable = false)
@Temporal(TemporalType.TIMESTAMP)
private Date lastTouched;

Por lo tanto, la columna de marca de tiempo se ignora al generar inserciones SQL. No estoy seguro de si esta es la mejor manera de hacerlo. Los comentarios son bienvenidos.

 46
Author: James McMahon,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-01-27 13:32:08

Me doy cuenta de que esto es un poco tarde, pero he tenido éxito al anotar una columna de marca de tiempo con

@Column(name="timestamp", columnDefinition="TIMESTAMP DEFAULT CURRENT_TIMESTAMP")

Esto también debería funcionar con CURRENT_DATE y CURRENT_TIME. Estoy usando JPA / Hibernar con Oracle, así que YMMV.

 30
Author: Matt Luongo,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-02-15 20:29:01

Esto funciona bien usando JPA2.0 y MySQL 5.5.10, para casos en los que solo me importa la última vez que se modificó la fila. MySQL creará una marca de tiempo en la primera inserción, y cada vez que se llame a UPDATE en la fila. (NOTA:esto será problemático si me importa si la ACTUALIZACIÓN realmente hizo un cambio o no).

La columna "timestamp" en este ejemplo es como una columna "last-touched".x '

El siguiente código utiliza una columna separada "versión" para el bloqueo optimista.

private long version;
private Date timeStamp

@Version
public long getVersion() {
    return version;
}

public void setVersion(long version) {
    this.version = version;
}

// columnDefinition could simply be = "TIMESTAMP", as the other settings are the MySQL default
@Column(name="timeStamp", columnDefinition="TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP")
@Temporal(TemporalType.TIMESTAMP)
public Date getTimeStamp() {
    return timeStamp;
}

public void setTimeStamp(Date timeStamp) {
    this.timeStamp = timeStamp;
}

(NOTA: @Version no funciona en una columna "DATETIME" de MySQL, donde el tipo de atributo es "Date" en la clase Entity. Esto se debió a que Date estaba generando un valor hasta el milisegundo, sin embargo MySQL no estaba almacenando el milisegundo, por lo que cuando hizo una comparación entre lo que estaba en la base de datos y la entidad "adjunta", pensó que tenían diferentes números de versión)

Del manual de MySQL con respecto a la MARCA DE TIEMPO :

With neither DEFAULT nor ON UPDATE clauses, it is the same as DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP.
 3
Author: willtardy,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-04-28 03:47:37

No creo que todas las bases de datos tengan marcas de tiempo de actualización automática (por ejemplo, Postgres). Así que he decidido actualizar este campo manualmente en todas partes de mi código. Esto funcionará con cada base de datos:

thingy.setLastTouched(new Date());
HibernateUtil.save(thingy);

Hay razones para usar disparadores, pero para la mayoría de los proyectos, este no es uno de ellos. Los disparadores te adentran aún más en una implementación de base de datos específica.

MySQL 5.6.28 (Ubuntu 15.10, OpenJDK 64-Bit 1.8.0_66) parece ser muy indulgente, no requiere nada beyond

@Column(name="LastTouched")

MySQL 5.7.9 (CentOS 6, OpenJDK 64-Bit 1.8.0_72) solo funciona con

@Column(name="LastTouched", insertable=false, updatable=false)

No:

FAILED: removing @Temporal
FAILED: @Column(name="LastTouched", nullable=true)
FAILED: @Column(name="LastTouched", columnDefinition="TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP")

Mi otra información del sistema (idéntica en ambos entornos)

  • hibernate-entitymanager 5.0.2
  • hibernate-validator 5.2.2
  • mysql-connector-java 5.1.38
 3
Author: GlenPeterson,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-02-17 17:25:04
@Column(nullable = false, updatable = false)
@CreationTimestamp
private Date created_at;

Esto funcionó para mí. más información

 2
Author: maximus,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-12-29 09:27:50