¿Cómo funciona la @Version
anotación en JPA?
Encontré varias respuestas cuyo extracto es el siguiente:
JPA usa un campo de versión en sus entidades para detectar modificaciones simultáneas en el mismo registro de almacén de datos. Cuando el tiempo de ejecución de JPA detecta un intento de modificar simultáneamente el mismo registro, lanza una excepción a la transacción que intenta confirmarse en último lugar.
Pero todavía no estoy seguro de cómo funciona.
También a partir de las siguientes líneas:
Debe considerar los campos de versión inmutables. Cambiar el valor del campo tiene resultados indefinidos.
¿Significa que deberíamos declarar nuestro campo de versión como final
?
java
jpa
jpa-annotations
Yatendra Goel
fuente
fuente
UPDATE myentity SET mycolumn = 'new value', version = version + 1 WHERE version = [old.version]
. Si alguien actualizó el registro,old.version
ya no coincidirá con el de la base de datos y la cláusula where evitará que se realice la actualización. Las 'filas actualizadas' serán0
, que JPA puede detectar para concluir que ocurrió una modificación concurrente.Respuestas:
Digamos que una entidad
MyEntity
tiene unaversion
propiedad anotada :En la actualización, el campo anotado con
@Version
se incrementará y se agregará a laWHERE
cláusula, algo como esto:Si la
WHERE
cláusula no coincide con un registro (porque la misma entidad ya ha sido actualizada por otro hilo), el proveedor de persistencia arrojará unOptimisticLockException
.No, pero podría considerar hacer que el colocador esté protegido, ya que se supone que no debe llamarlo.
fuente
long
o simplemente en llamarlolongValue()
. Necesitanull
controles explícitos . Inicializarlo explícitamente usted mismo no lo haría, ya que se supone que este campo lo administra el proveedor de ORM. Creo que se establece0L
en la primera inserción en la base de datos, por lo que si está configurado ennull
esto, le indica que este registro aún no se ha conservado.Long
lugar de una primitivalong
para el@Version
campo, porqueSimpleJpaRepository.save(entity)
probablemente tratará un campo de versión nula como un indicador de que la entidad es nueva. Si la entidad es nueva (como indica que la versión es nula), Spring llamaráem.persist(entity)
. Pero si la versión tiene un valor, llamaráem.merge(entity)
. Esta es también la razón por la que un campo de versión que se declara como un tipo de contenedor debe dejarse sin inicializar.Aunque la respuesta de @Pascal es perfectamente válida, desde mi experiencia, encuentro que el siguiente código es útil para lograr un bloqueo optimista:
¿Por qué? Porque:
@Version
se establece accidentalmente ennull
.optlock
aversion
.Primer punto no importa si utiliza la aplicación única APP para insertar datos en la base de datos, como proveedor JPA hará cumplir
0
de@version
campo durante la creación. Pero casi siempre también se utilizan sentencias SQL simples (al menos durante las pruebas unitarias y de integración).fuente
u_lmod
(usuario modificado por última vez) donde el usuario puede ser un humano o un proceso / entidad / aplicación definida (automatizada) (por lo que almacenar adicionalmente tambiénu_lmod_id
podría tener sentido). (En mi opinión, es un metaatributo empresarial muy básico). Por lo general, almacena su valor como FECHA (HORA) (es decir, información sobre el año ... milis) en UTC (si es importante almacenar la "ubicación" de la zona horaria del editor, entonces con la zona horaria). además, es muy útil para escenarios de sincronización DWH.Cada vez que se actualiza una entidad en la base de datos, el campo de versión aumentará en uno. Cada operación que actualice la entidad en la base de datos se agregará
WHERE version = VERSION_THAT_WAS_LOADED_FROM_DATABASE
a su consulta.Al verificar las filas afectadas de su operación, el marco jpa puede asegurarse de que no haya una modificación simultánea entre la carga y la persistencia de su entidad porque la consulta no encontraría su entidad en la base de datos cuando su número de versión se ha incrementado entre la carga y la persistencia.
fuente
Versión utilizada para garantizar que solo se actualice una vez por vez. El proveedor de JPA verificará la versión, si la versión esperada ya aumentó, entonces alguien más ya actualizó la entidad, por lo que se lanzará una excepción.
Entonces, actualizar el valor de la entidad sería más seguro, más optimista.
Si el valor cambia con frecuencia, entonces podría considerar no usar el campo de versión. Por ejemplo, "una entidad que tiene un campo contador, que aumentará cada vez que se acceda a una página web".
fuente
Solo agrego un poco más de información.
JPA administra la versión bajo el capó por usted, sin embargo, no lo hace cuando actualiza su registro a través de
JPAUpdateClause
, en tales casos, debe agregar manualmente el incremento de la versión a la consulta.Lo mismo se puede decir sobre la actualización a través de JPQL, es decir, no un simple cambio en la entidad, sino un comando de actualización de la base de datos, incluso si se hace mediante hibernación.
Pedro
fuente
JPAUpdateClause
?