0

I am trying to write a code which will query account records and lock them using FOR UPDATE keyword and then I am also triggering another batch which will try tu update same record with some more records of account. But even after using Database.update(xyz,false) I am getting error lock for all other records as well even if we are using Database.update

Can anyone please help me. Below is sample code snippet:

First i am executing below code to lock the specific record:

Account act = [SELECT Id FROM Account WHERE Id = '0010I00002DmyzG' FOR UPDATE];
for (Integer index = 0; index < 44444; index ++ ) {
 for (Integer index1= 0; index1 < 44444; index1++ ) {

 }
}

Secondly I am executing below code to update the same record used above with two separate records but even if I am using database.update I am getting row lock error for other two records as well

Set<Id> cSet = new Set<Id>();
cSet.add('0010I00002DmyzG');
ctSet.add('0010I00002Dmyv7');
cSet.add('00128000009iR8y');

List<Account> ctrList = new List<Account>();
for (Account ct : [
 SELECT Active__c FROM Account WHERE Id IN :cSet]) {
 ct.Active__c = 'Yes';
 ctrList.add(ct);
}

Thanks

  • 3
    Firstly the FOR UPDATE will execute in a different session to the batch and can therefore clash. Next the batch execution could happen at any time after the Database.executeBatch call - the Salesforce multi-tenant servers can delay it as long as needed to ensure compute resources are available. What is it you are actually trying to do? Are you simply wondering what the locking scope is and whether locking "bleeds out" to other records in record blocks within the Database? – Phil W Aug 31 at 12:47
1

The row-locking mechanism will always throw an exception if a lock is not acquired in about ten seconds. This behavior helps prevent deadlocks/infinite loops. When using FOR UPDATE, you should be aware of that feature. If you think you'll need more time, you can catch the exception and try again.

Please note that you should always use FOR UPDATE for queries in which you plan to update records, and you should always lock parents before children, if applicable (e.g. Accounts first, Contacts second). As an example of your code, the following change would work:

Set<Id> cSet = new Set<Id>();
cSet.add('0010I00002DmyzG');
cSet.add('0010I00002Dmyv7');
cSet.add('00128000009iR8y');

while(true) {
  try {
    List<Account> ctrList = new List<Account>();
    for (Account ct : [
        SELECT Active__c FROM Account WHERE Id IN :cSet FOR UPDATE]) {
      ct.Active__c = 'Yes';
      ctrList.add(ct);
    }
    Database.update(ctrList, false);
    break; // Stop infinite loop
  } catch(QueryException e) {
}

By querying first, we make sure we get a row lock, or fail with an exception, which we retry until we reach governor limits or succeed.

  • According to the docs a QueryException is thrown after 10 seconds when an exclusive lock cannot be obtained. Also, parent records are automatically locked as a side-effect of locking children IIRC. – Phil W Aug 31 at 14:58
  • Worth also noting that batchables automatically perform the row locking for you (FOR UPDATE cannot be used with a query locator). The docs say this is during start, but I believe that is not true and that it is around each call to execute (which is when data is loaded - start just grabs the full set of IDs I believe). – Phil W Aug 31 at 15:01
  • @PhilW (a) Nice to see they've increased the limit from 5 seconds (b) the records are initially locked during start, and "scope" should be locked for each execute. For start methods, all fields and relationships in the query locator are stored for later processing, not just the ID value. That's why I recommend requerying records during the execute method. Also, including more fields slows down the start method, which can cause timeout exceptions. – sfdcfox Aug 31 at 15:17
  • @PhilW Also, see Avoiding Deadlocks. While there is some automatic support for locking parents then children, it's usually better to be explicit and lock records in a specific order throughout your app. – sfdcfox Aug 31 at 15:19
  • Now, it is on a different website, but check what is said here about how batches handle the querying. This is what I have based my understanding on. – Phil W Aug 31 at 16:40

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.