A lock is always necessary to update a record, but a transaction might already have a lock on the record you want to update, so you don't necessarily need FOR UPDATE
in every query.
Performing a DML on a Contact, for example, also automatically locks the Account for that Contact. If you want to update the Account in a trigger, or even after performing a DML operation on the Contact, you can logically assume that the Account is already locked, and you have priority to performing an update on the Account.
In addition, a DML statement has a period of time where it will wait to try and acquire a lock. This means that small, fast updates don't necessarily need to acquire a lock explicitly. However, as you found, this is how you get an UNABLE_TO_LOCK_ROW
exception.
The documentation team tends to focus on specific features in their own area. That's why you don't see an entry for FOR UPDATE
in the SOQL Developer's Guide, because you can't use it in normal SOQL. Each core documentation has a target audience, and the teams try to write for that audience. Ultimately, the FOR UPDATE
keyword only appears in a couple of documents that address row lock.
The fact is, as long as you're obeying the basic principles laid out by salesforce.com, FOR UPDATE
is largely unnecessary. The two main rules you should follow are to avoid Lookup Skew and Ownership Skew, and writing your code to be as efficient as possible, ideally no transactions over 5 seconds of CPU time.
Most small to medium orgs can operate with exactly zero uses of FOR UPDATE
. It's not until you start getting into the large orgs that explicit locking is really necessary. I think they probably could put a little more emphasis on it, but really not much is needed. Salesforce is usually very capable of managing row locks for developers, as long as they don't write inefficient code.
Edit:
The main reason why FOR UPDATE exists is to make sure that no other transaction can change the record before the current transaction has completed, as well as make sure that no other transaction's DML operations might be overridden. Because the query waits for the lock, and no DML operation can occur on a row-locked record, you can guarantee data consistency.
A normal SOQL query without FOR UPDATE can retrieve stale data, while a query with FOR UPDATE will wait until all previous locks on those records (either by FOR UPDATE or by implicit DML locks) have completed before continuing. DML statements themselves will simply throw an UNABLE_TO_LOCK_ROW error if a lock can't be acquired in a very short time window.
FOR UPDATE
doesn't supportORDER BY
if that is important to your app