views:

26

answers:

2

Hello, i've got some problems with transactions when there is the exception java.util.ConcurrentModificationException.

When i've got this exception, i tried a retry but when i'm looking in my datastore viewer my incrementation didn't work.

For example when i'm testing with 30 simultaneous users, my data was incremented 28 times. 2 incrementations are missing and i've got 2 java.util.ConcurrentModificationException.

Somebody knows why? How can i solve this problem.

int answerNb = Integer.parseInt(req.getParameter("answer"));
PersistenceManager pm = PMF.get().getPersistenceManager();
Query query = pm.newQuery("select from " + Question.class.getName());
query.setFilter("date == dateParam");
query.declareParameters("String dateParam");
List<Question> questions = (List<Question>) query.execute(req.getParameter("date"));

if(!questions.isEmpty()) {
    int retryCount = 0;
    while (retryCount++ < 30) {
      pm.currentTransaction().begin();
      questions.get(0).getAnswers().get(answerNb).increment();

      try {
         pm.currentTransaction().commit();
         break;
      }
      catch (Exception x) {
         //retry
      }
  }

my method increment in a java class

public void increment() {
    counter ++;
}
A: 

Use Vector instead of List. When you run the query and return a list, modifications of that list are persisted in the datastore when the transaction is committed. Therefore, if you have many users trying to modify this list at once, you'll run into this exception because they are all trying to modify the same list that is in the datastore. Use Vector, since it is synchronized, and your problem will go away.

Travis J Webb
How do you do ? Because the query can't be cast to Vector. For example when i'm trying Vector<Question> questions = (Vector<Question>)query.execute(req.getParameter("date"));I've got this :org.datanucleus.store.appengine.query.StreamingQueryResult cannot be cast to java.util.Vector
ld493
A: 

I solve my problem by using key and the method pm.getObjectById instead of query

int answerNb = Integer.parseInt(req.getParameter("answer"));            
int retryCount = 0;
Transaction tx;
Question question;

while (retryCount++ < 30) {
  PersistenceManager pm = PMF.get().getPersistenceManager();
  tx = pm.currentTransaction();
  tx.begin();
  question = pm.getObjectById(Question.class,KeyFactory.stringToKey(req.getParameter("key")));          
  question.getAnswers().get(answerNb).increment();
  try {
    tx.commit();
    pm.close();
    break;
  }
  catch (Exception x) {
    pm.close();
    log.info("retry : "+retryCount);
  }
}
ld493