Saltar al contenido

Cómo actualizar el campo @Version al ejecutar una actualización masiva a través de Spring Data JPA

Buscamos en internet y así darte la respuesta para tu duda, si tienes dudas déjanos la pregunta y te responderemos con gusto, porque estamos para servirte.

Solución:

La sección 4.10 de la especificación JPA 2.0 establece explícitamente:

La actualización masiva se asigna directamente a una operación de actualización de la base de datos, sin pasar por las comprobaciones de bloqueo optimistas. Las aplicaciones portátiles deben actualizar manualmente el valor de la columna de versión, si se desea, y/o validar manualmente el valor de la columna de versión.

En términos generales, las actualizaciones y eliminaciones masivas pasan por alto una gran cantidad de funciones que aplica el proveedor de persistencia al que podría estar acostumbrado cuando simplemente guarda una entidad. Además del bloqueo optimista, esto incluye la cascada administrada por el proveedor de persistencia de las operaciones de persistencia.

Para utilizar el bloqueo optimista, necesita un version columna primero.

Ahora, si la declaración de actualización masiva no incrementa el version columna, puede ocurrir una anomalía de actualización perdida:

Actualización masiva actualización perdida

Ahora, para evitar la actualización perdida, solo necesita incrementar la version columna.

Puedes hacerlo con cualquier tipo de consulta.

JPQL

int updateCount = entityManager
.createQuery(
    "update Post " +
    "set " +
    "   status = :newStatus," +
    "   version = version + 1 " +
    "where " +
    "   status = :oldStatus and " +
    "   lower(title) like :pattern")
.setParameter("oldStatus", PostStatus.PENDING)
.setParameter("newStatus", PostStatus.SPAM)
.setParameter("pattern", "%spam%")
.executeUpdate();

API de criterios

CriteriaBuilder builder = entityManager
.getCriteriaBuilder();
 
CriteriaUpdate update = builder
.createCriteriaUpdate(Post.class);
 
Root root = update.from(Post.class);
 
Expression wherePredicate = builder
.and(
    builder.equal(
        root.get("status"),
        PostStatus.PENDING
    ),
    builder.like(
        builder.lower(root.get("title")),
        "%spam%"
    )
);
 
Path versionPath = root.get("version");
Expression incrementVersion = builder
.sum((short) 1, versionPath);
 
update
.set(root.get("status"), PostStatus.SPAM)
.set(versionPath, incrementVersion)
.where(wherePredicate);
 
int updateCount = entityManager
.createQuery(update)
.executeUpdate();

SQL nativo

UPDATE post
SET
  status = 2,
  version = version + 1
WHERE
  status = 0 AND 
  lower(title) LIKE '%spam%'

Una vez que incrementes el version columna, la actualización perdida se evitará en las transacciones concurrentes que cargaron las versiones anteriores de las entidades actualizadas por la declaración masiva:

Actualización masiva con bloqueo optimista

Aquí puedes ver las reseñas y valoraciones de los lectores

¡Haz clic para puntuar esta entrada!
(Votos: 0 Promedio: 0)



Utiliza Nuestro Buscador

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *