The following JDO 2 example demonstrates optimistic lock exception (it should work the same way also in JPA 2):
package com.objectdb.example;
import java.util.*;
import javax.jdo.*;
import javax.jdo.annotations.*;
public class OptimisticLockExceptionExample {
public static void main(final String[] args) {
// Create a new database:
Properties properties = new Properties();
properties.setProperty(
"javax.jdo.PersistenceManagerFactoryClass", "com.objectdb.jdo.PMF");
properties.setProperty("javax.jdo.option.ConnectionURL", "db.odb");
PersistenceManagerFactory pmf =
JDOHelper.getPersistenceManagerFactory(properties);
// Persist one Counter object:
PersistenceManager pm = pmf.getPersistenceManager();
pm.currentTransaction().begin();
pm.makePersistent(new Counter());
pm.currentTransaction().commit();
pm.close();
// First user retrieves and updates the Counter:
PersistenceManager pm1 = pmf.getPersistenceManager();
Counter c1 = pm1.getExtent(Counter.class).iterator().next();
pm1.currentTransaction().begin();
c1.increase();
// Second user retrieves and updates the Counter:
PersistenceManager pm2 = pmf.getPersistenceManager();
Counter c2 = pm2.getExtent(Counter.class).iterator().next();
pm2.currentTransaction().begin();
c2.increase();
// First user commits - succeeds:
pm1.currentTransaction().commit();
pm1.close();
// Second user commits - fails with JDOOptimisticVerificationException:
pm2.currentTransaction().commit();
pm2.close();
// Close the database:
pmf.close();
}
@PersistenceCapable
static class Counter {
private int count;
void increase() {
count++;
}
}
}
For optimistic locking to work each user should have its own PersistenceManager and the update must be based on the object that was retrieved from the database.
For example, if you retrieve an object, copy its data to a temporary data structure for presentation and then on update retrieves the object again and fills its with the data from the temporary data structure - then updates of other users might be overridden.