Class GuardedUpdate
UPDATE ... WHERE whose row count decides a winner.
This is how the workflow engine claims work across a cluster: several nodes fire the same guarded update, the database lets exactly one of them match, and the loser sees zero rows. Every claim, lease and one-way status flip in the engine settles this way, so the guarantee has to be real on the databases we ship on -- not just on the one the tests happen to run against.
Deliberately not Query.update(Map): that rewrites the predicate into
WHERE self.id IN (SELECT that.id FROM ... WHERE <predicate>). PostgreSQL evaluates that
subplan against the snapshot the statement began with, and its recheck after waiting on a
concurrent writer's row lock re-tests only the outer qualifiers. So a blocked claimant wakes up,
re-reads nothing, and updates the row anyway: every racer reports one row and every racer
believes it won. HSQLDB serialises writers and hides the difference, which is why this only ever
shows up on a real server.
Writing the predicate directly in the UPDATE's own WHERE clause is what makes
the recheck happen against the committed row version, so exactly one caller wins.
Like any bulk update this bypasses the persistence context and does not bump version;
callers that go on to touch the entity must refresh it, and callers that need the version moved
must set it themselves.
-
Nested Class Summary
Nested ClassesModifier and TypeClassDescriptionstatic final recordAn assignment that is HQL rather than a value. -
Method Summary
Modifier and TypeMethodDescriptionintexecute()Run the update and return the number of rows it matched.static GuardedUpdate.HqlAssignfieldthe HQLexpression, evaluated by the database.static GuardedUpdateAssignfield; a null value is emitted as a literal, not a parameter.Assign every entry offields, in iteration order.The guard, as JPQL over theselfalias.booleanwins()Whether this caller is the one that took the row.
-
Method Details
-
on
-
hql
Assignfieldthe HQLexpression, evaluated by the database. -
set
Assignfield; a null value is emitted as a literal, not a parameter. -
setAll
Assign every entry offields, in iteration order. -
where
The guard, as JPQL over theselfalias. -
bind
-
execute
public int execute()Run the update and return the number of rows it matched. -
wins
public boolean wins()Whether this caller is the one that took the row.
-