Preventing Lost Updates in Mongo With Spring Optimistic Locking

Spring provides @Version notation for optimistic locking. Simply add a field to your entity with that annotation. E.g.

import org.springframework.data.annotation.Version

@Version
private Long version

Note: Long not long.

Once you’ve done this an OptimisticLockingFailureException will be thrown if a lost update is about to occur thereby preventing it.

One thing you would probably want to do is retry the update automatically for a while since the lost update situation will probably resolve itself so that you can do the update without any loss. Spring provides for that as well.

Say, you have a method, updateSum(int x, int summaryId), that picks a Summary object from your collection and updates its sum:

public void updateSum(int x, int summaryId){
 Summary summary = getFromDb(summaryId);
 summary.setSum(summary.getSum() + x);
 saveSummary(summary);
}

With version added to Summary, a Spring Framework OptimisticLockingFailureException will be thrown if a lost update is about to occur. To retry your update, you could do this:

import org.springframework.retry.RecoveryCallback;
import org.springframework.retry.RetryCallback;
import org.springframework.retry.RetryContext;
import org.springframework.retry.policy.SimpleRetryPolicy;
import org.springframework.retry.support.RetryTemplate;
import org.springframework.dao.OptimisticLockingFailureException;

public void updateSumWithRetry(final int x, final int summaryId){
 RetryTemplate template = new RetryTemplate();
 Map<class extends="" throwable="">, Boolean> map = 
        new HashMap<Class, Boolean>();
 map.put(OptimisticLockingFailureException.class, true);

 //Initialized with the number of retries (i.e. 20) and a map of exceptions 
 //for which it should be retried
 SimpleRetryPolicy policy = new SimpleRetryPolicy(20, map);
 template.setRetryPolicy(policy);
 template.execute(new RetryCallback<boolean>() {
   public Boolean doWithRetry(RetryContext context) throws Exception {
     updateSum(x, summaryId)
   }
  },
  new RecoveryCallback<boolean>() {
    public Boolean recover(RetryContext context) throws Exception {                
    //specify what to do in case of failure after all retries             
    }        
  }    
 } 
} 

RecoveryCallback is executed if the retries fail after the specified attempts.

You require spring-retry:

<dependency>     
  <groupid>org.springframework.retry</groupid>     
  <artifactid>spring-retry</artifactid>    
  <version>1.0.3.RELEASE</version>    
</dependency>
Advertisement

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s