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:
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: