Print this page

Race condition between Apex code and API Call

Knowledge Article Number 000220286
Description In the following apex code, there's a possibility that the assert statement will fail if an API transaction executing in parallel was able to update the LastName. Select statement (with For update) will try to lock the record. But if record is already locked then it'll still select the record but wait for lock to be released (for 10 seconds). If record is released then second transaction will continue. 

List<Contact> myContactList = [SELECT Id, LastName FROM Contact where LastName = 'mylast' FOR UPDATE];
for (Contact c : myContactList){
System.assertEquals('mylast', c.LastName.toLowerCase());
}
Resolution There's a possibility that the assert statement will fail if an API transaction executing in parallel was able to update the LastName. Select statement (with For update) will try to lock the record. But if record is already locked then it will still select the record but wait for lock to be released (for 10 seconds). If record is released then second transaction will continue. 

The locking process returns a fresh copy of the record from the database through the SELECT statement. But it doesn't really run select statement again. It just does it "internally" to refresh the data of record which was already selected in the actual SOQL. So we have to check if the where clause filter is still valid.


 
List<Contact> myContactList = [SELECT Id, LastName FROM Contact where LastName = 'mylast' FOR UPDATE];
for (Contact c : myContactList){
if (c.LastName == 'mylast')
{System.assertEquals('mylast', c.LastName.toLowerCase());}
}


The behavior is also explained in the doc: https://www.salesforce.com/us/developer/docs/apexcode/Content/langCon_apex_locking_statements.htm




promote demote