Override Optimistic Lock and persist stale entity in Hibernate

In real time application, There could be a scenario to tell the hibernate not to allow concurrent update of an entity. Optimistic lock can be used to accomplish it, It never locks the underlying record in the DB rather it needs either Version or Timestamp column to determine whether the entity is up-to-date or stale.

 

@Column( name = "VERS", nullable = false )
@Version

private Long vers;

Version column is being updated automatically whenever entity is been udpated. Hibernate uses this version column value to check for stale. Second concurrent process which is updating this entity will receive OptimisticLockException/StaleObjectException.

If you want stale object to be updated  by any cause, use the following Spring AOP approach.Configure the following beans in your spring-beans.xml

 <bean id="retryingTransactionInterceptor">    
  <property name="order" value="1" />
  </bean>  
  <aop:config>     
   <aop:aspect id="retryingTransactionAspect" ref="retryingTransactionInterceptor">         
     <aop:pointcut  id="servicesWithRetryingTransactionAnnotation" expression="execution( * examples.service..*.*(..) ) 
     and @annotation(examples.annotation.RetryingTransaction)"/>         
     <aop:around method="retryOperation" pointcut-ref="servicesWithRetryingTransactionAnnotation"/>     
   </aop:aspect> 
  </aop:config>

 

 
package examples.annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target( {
 ElementType.METHOD
} )
@Retention( RetentionPolicy.RUNTIME )
public @interface RetryingTransaction {
 int repeatCount() default 20;
}

 

@Transactional
 @RetryingTransaction
 public Test merge( Test test ) {
  return testDao.merge( test );
 }

 

package examples;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import javax.persistence.OptimisticLockException;
import javax.persistence.Version;
import org.aspectj.lang.ProceedingJoinPoint;
import org.hibernate.property.BasicPropertyAccessor;
import org.springframework.core.Ordered;
public class RetryingTransactionInterceptor implements Ordered {
 private static final int DEFAULT_MAX_RETRIES = 20;
 private int maxRetries = DEFAULT_MAX_RETRIES;
 private int order = 1;
 public void setMaxRetries( int maxRetries ) {
  this.maxRetries = maxRetries;
 }
 public int getOrder() {
  return this.order;
 }
 public void setOrder( int order ) {
  this.order = order;
 }
 public Object retryOperation( ProceedingJoinPoint pjp ) throws Throwable {
  int numAttempts = 0;
  Exception failureException = null;
  Object obj = null;
  Object arg1 = null;
  do {
   numAttempts++;
   try {
    Object[] obje = pjp.getArgs();
    arg1 = (Test) obje[ 0 ];
    obj = pjp.proceed();
    return obj;
   } catch ( RuntimeException re ) {
    failureException = re;
    System.out.println( "OptimisticLockException:"
      + ( (OptimisticLockException) re.getCause() ).getEntity() );
    incrementVersion( arg1 );
   }
  } while ( numAttempts <= this.maxRetries );
  throw failureException;
 }
 private Object incrementVersion( Object entityObject ) throws IllegalAccessException,
  InvocationTargetException, NoSuchMethodException {
  Object idValue = null;
  for ( Field field : entityObject.getClass().getDeclaredFields() ) {
   BasicPropertyAccessor basicGetter = new BasicPropertyAccessor();
   if ( field.getAnnotation( Version.class ) != null ) {
    System.out.println( "Id value:"
      + basicGetter.getGetter( entityObject.getClass(), field.getName() ).get(
       entityObject ) );
    idValue =
      basicGetter.getGetter( entityObject.getClass(), field.getName() ).get(
       entityObject );
    basicGetter.getSetter( entityObject.getClass(), field.getName() ).set(
     entityObject, (Long) idValue + 1, null );
    break;
   }
  }
  return idValue;
 }
}

Above code catches the OptimisticLock ,increase the version value and persist the stale
entity . You can also achieve it using simple update query too. It is up to
you to take correct decision.  

 

Advertisements

How to lazy load one to one related entity in hibernate JPA?

Hibernate does not support one-to-one lazy loading.

Work around is marking one-to-many relationship in parent end and one-to-one in child end.

In Parent

@OneToMany( mappedBy = "parent", fetch = FetchType.LAZY, cascade = CascadeType.ALL )
private List<Child> childs;

In Child

@OneToOne( )
@JoinColumn( name = "child_id", referencedColumnName = "parent_id" )
private Parent parent;

Atomic Integer handles concurrency smartly & efficiently

Atomic integer is used to handle concurrency of increment and decrement operation smartly using a non-blocking algorithm.

Also it improves the execution time when compared to synchronized way of handling concurrency.

import java.util.concurrent.atomic.AtomicInteger;
public class AtomicIntegerTest {
 public static void main(String[] args) {
  AtomicInteger counter = new AtomicInteger(0);
  for(int i=0; i<50; i++) {
   Runnable runnable = new WorkerThread(counter);
   Thread t = new Thread(runnable);
   t.start();
  }
 }
}
class WorkerThread implements Runnable {
 AtomicInteger count = null;
 WorkerThread(AtomicInteger counter) {
  this.count = counter;
 }
 public void run() {
  int value = this.count.incrementAndGet();
  System.out.println(value);
 }
}

 Above problem spans 50 threads and does increment operation.

You can notice that it prints number between 1 and 50 without a duplicate value which ensures the concurrency.

Copy , Paste and Transfer files with remote desktop connection to and from your remote computer

1. Open Start>>Run and type mstsc

2. Now click on options and again click on Local Resources Tab.

3. Under Local Devices and Resources (in vista) ,click on more.. button. ( In Windows Xp ) you will see a checkbox as Local Drives

4. Check the Checkbox “drives” in the newly opened window in vista or check the checkbox Local Drives in Windows XP.

5. Click OK and connect to the remote computer now.