April 13, 2011

Visualizing Record Locking in SOQL i.e. for update !

Today, I came across this interesting tweet.

Luckily Smile I knew the answer, and found the same in apex docs too i.e.

“While an sObject record is locked, no other program or user is allowed to make updates.”

But a “t” germ inside me provoked to test this out and create a POC to see “FOR UPDATE” in action, I want to see what crash/error comes, when one attempts to update a locked record from other user !

So, I tried to create a multi-user scenario updating  same locked records in various ways like

  1. Visualforce page & Apex Controller
  2. Apex Test class to simulate two users

Failed approach - Visualforce page & Apex Controller

I created a visualforce page that does a lot of things after locking some Account records. These lot of things include:  call outs, iterating nearly 1,90,000 times to add extra delay and still stay out of governor attacks. But this can’t succeed as it was really next to impossible to time two users in two browsers hit the page at exact same interval. So dumped this silly experiment, without wasting any more time #@$#$ Winking smile

Apex test class to simulate two users – need your views here !

Create an Apex test class that tries to simulate the same using System.runAs().

My use case(scenario) was to create a test method in this class that :

  • Creates an account from the logged in user.
  • Query that same account back using “for update”.
  • Start new context using “System.runAs()” from some other user i.e. not the logged in user.
  • Try updating the same locked account, using that other simulation user.

Here is the apex test class, if you want to experiment.

public class TestRecordLocking {
  testmethod public static void testLocking() {
    // create a account from logged in user
    Account accoutU1 = new Account(Name = 'Abhinav Gupta');
    insert accoutU1;
    // lock the same account    
    accoutU1 = [Select Id, Name, Website from Account where Id =:accoutU1.id for update];
    
    //Start updating it
    accoutU1.website = 'www.salesforce.com';
    
    // Now lets say, some other user comes and tries to update the same record
    User u2 = [Select Id from user where id !=:UserInfo.getUserId() limit 1];
    System.runAs(u2) {
    // other user queries the same account 
      Account accountU2 = [Select Id, Name, Website from Account where Id =:accoutU1.id ];
    // other user tries to update it
      accountU2.WebSite = 'www.yahoo.com';
      update accountU2;      
    }
    
    // Now update the original account back.
    update accoutU1;    
  }  
}

Expected Result on Executing this Apex Test ?

It should fail, isn’t ? As I am trying to update record locked by some other user. Unfortunately it works like a charm. I believe, System.runAs() is not creating exact multi user context that might be created in real life ?

Please let me know your views and ideas on this ?