Package com.axelor.db

Class GuardedUpdate

java.lang.Object
com.axelor.db.GuardedUpdate

public final class GuardedUpdate extends Object
A conditional 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.

  • Method Details

    • on

      public static GuardedUpdate on(Class<? extends Model> entity)
    • hql

      public static GuardedUpdate.Hql hql(String expression)
      Assign field the HQL expression, evaluated by the database.
    • set

      public GuardedUpdate set(String field, Object value)
      Assign field; a null value is emitted as a literal, not a parameter.
    • setAll

      public GuardedUpdate setAll(Map<String,Object> fields)
      Assign every entry of fields, in iteration order.
    • where

      public GuardedUpdate where(String jpql)
      The guard, as JPQL over the self alias.
    • bind

      public GuardedUpdate bind(String name, Object value)
    • 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.