Skip to main content

SF-0282 · Concept · Hard

What is the benefit of a Locking statement?

✓ Verified by Vikas Singhal · Last reviewed 5/17/2026 · Updated for Spring '26

The FOR UPDATE clause on a SOQL query — the locking statement — is how you prevent lost updates in a multi-user system. Without it, two concurrent transactions can both read the same record, both compute new values, and both write — the second write silently overwrites the first.

The race that FOR UPDATE prevents

Transaction A                Transaction B
---------------              ---------------
SELECT Balance: 100
                             SELECT Balance: 100
Balance := 100 + 50 = 150
                             Balance := 100 - 30 = 70
UPDATE to 150
                             UPDATE to 70   ← A's update silently lost

After both transactions commit, the balance is 70. The +50 deposit from A is gone.

With FOR UPDATE

Account a = [SELECT Id, Balance__c FROM Account WHERE Id = :acctId FOR UPDATE];
a.Balance__c += amount;
update a;

Now the second transaction blocks at its SELECT ... FOR UPDATE until the first one commits or rolls back. When B is finally allowed to read, it sees the post-A balance and computes the correct result.

Where the lock is held

A FOR UPDATE lock is taken on the specific row(s) returned by the query. The lock is released when the transaction commits or rolls back. It is NOT held across:

  • HTTP callouts (the platform releases the lock before the callout, takes it back after — risky)
  • Async chains (each async transaction is fresh)
  • Database.rollback() to a savepoint — but the transaction still holds it until tx end

The cost of locking

Locks aren’t free. They:

  • Reduce concurrency — other transactions trying to touch the same row queue up behind yours.
  • Risk deadlocks — two transactions each waiting for a row the other holds. Salesforce’s deadlock detector eventually kills one, but the user sees an error.
  • Cost CPU/throughput on the database tier — measured in your shared tenant budget.

Rule of thumb: lock only when you actually have a read-modify-write that must be atomic.

When FOR UPDATE is the right tool

  • Inventory or balance updates that depend on the current value.
  • Counter increments (Updated_Count__c += 1).
  • “First user to claim this record wins” pickers.
  • Sequence number generation (you read the next number, increment, write back).

When it isn’t

  • Blind writesupdate new Account(Id = id, Status__c = 'Won') doesn’t need a lock; it overwrites whatever was there.
  • Read-only queries — no DML coming, no lock needed.
  • Bulk imports where conflicts are rare — the cost of locking exceeds the cost of occasional conflicts that you handle by retrying.

What the platform already locks for you

Even without FOR UPDATE, Salesforce implicitly locks records during DML. Any update myRecords takes row-level locks until the transaction ends. So:

  • Two update Account transactions touching the same record will serialize anyway.
  • The risk FOR UPDATE prevents is specifically the read-then-write case where the read isn’t itself a DML.

FOR UPDATE only takes the lock on the directly queried rows. Child records and parent records are NOT auto-locked. If your logic depends on parent + child consistency, you query both with FOR UPDATE:

Account a = [SELECT Id, Balance__c FROM Account WHERE Id = :acctId FOR UPDATE];
List<Transaction__c> txs = [
    SELECT Id, Amount__c FROM Transaction__c
    WHERE Account__c = :acctId AND Status__c = 'Pending'
    FOR UPDATE
];
// ... compute new balance from txs, update a

Failure mode: UNABLE_TO_LOCK_ROW

If the lock isn’t acquired within the timeout (about 10 seconds by default), the runtime throws:

UNABLE_TO_LOCK_ROW: unable to obtain exclusive access to this record

In production, this is the most common locking failure. Fixes:

  • Shorten the work inside the lock (do read, then DML, then release — fast).
  • Don’t FOR UPDATE thousands of rows when only a few are contended.
  • Retry the transaction (most ORMs and the platform do this automatically up to a point).

What interviewers are really looking for

The basic answer is “prevents lost updates.” The senior answer adds: (1) FOR UPDATE is for read-modify-write atomicity, (2) DML already locks implicitly — FOR UPDATE only matters before the DML, (3) locks don’t survive callouts cleanly, (4) UNABLE_TO_LOCK_ROW is the production failure to recognise, (5) over-locking causes deadlocks and reduced concurrency — only lock what you must.

Verified against: Apex Developer Guide — Locking Statements, SOQL FOR UPDATE. Last reviewed 2026-05-17.