The SOQL doc states that FOR UPDATE
is available for inline SOQL
To lock a set of sObject records in Apex, embed the keywords FOR UPDATE after any inline SOQL statement. For example, the following statement, in addition to querying for two accounts, also locks the accounts that are returned:
Account [] accts = [SELECT Id FROM Account LIMIT 2 FOR UPDATE];
But what about dynamic SOQL?
Account [] accts = Database.query('SELECT Id FROM Account LIMIT 2 FOR UPDATE');
The Dynamic SOQL doc doesn't say you can't use it and I know you don't get an error if you do use it – but perhaps the FOR UPDATE
is just ignored. That would be bad.
Best Answer
You can't test record locking in testmethods so you'll need to use Execute Anonymous and some simulator that forces the
FOR UPDATE
locking conditionI borrowed from Dan Appleman's 4th Edition Advanced Apex Programming Chapter 8 Concurrency Handling DML Lock errors, pages 192-6 for a simulator:
You can see I experimented with both inline and dynamic SOQL. The tester assumes there is an Opportunity with Name =
ConcurrencySimulator
(yes - I could have made this more generalized)Using execute anonymous, I initiated two future transactions in one go:
By examining the respective future debug logs, it was easy to see that one of the two future transactions had to wait "several" seconds before returning the SOQL's 1 row.
Hence,
FOR UPDATE
works in dynamic SOQL.Conclusion: Documentation needs amending.
If anyone has a counter-argument, please post a separate answer.