7

When I execute:

public void beginTransaction() {
    em.getTransaction().begin();
}

following an active transaction started in the same way, I get the following exception:

Exception Description: Transaction is currently active
java.lang.IllegalStateException: 
Exception Description: Transaction is currently active
        at org.eclipse.persistence.internal.jpa.transaction.EntityTransactionImpl.begin(EntityTransactionImpl.java:45)
        at com.mysimpatico.memoplatform.persistence.Database.beginTransaction(Database.java:44)
        at com.mysimpatico.memoplatform.persistence.tests.PersistenceTest.setUp(PersistenceTest.java:39)

The underlying DBMS is embedded apache derby which to my knowledge doesn't support multiple connections from different JVMS, but otherwise supports concurrent transactions.Documentation

This test code fails:

public <Entity> int getNo(final Class<Entity> entityClass) {
    final CriteriaBuilder qb = em.getCriteriaBuilder();
    final CriteriaQuery<Long> cq = qb.createQuery(Long.class);
    cq.select(qb.count(cq.from(entityClass)));
    final int ret = em.createQuery(cq).getSingleResult().intValue();
    return ret;
}

protected void insertWords(final List<String[]> expressionDefTriples, MUser usr, final MeaningsDatabase mengsDB) throws Exception {
    for (String[] expressionDefTriple : expressionDefTriples) {
        mengsDB.persistSynonyms(MeaningsDatabase.toEnumMap(expressionDefTriple, usr));
        testSynonymsPersistance(expressionDefTriple,mengsDB);
    }
}

protected void testSynonymsPersistance(final String[] expDefTriple, final MeaningsDatabase mengsDB) {
    final Expression exp = mengsDB.get(Expression.class, expDefTriple[0]);
    testGender(exp, expDefTriple[2]);
    final Expression def = mengsDB.get(Expression.class, expDefTriple[1]);
    assertNotNull(def);
    assertTrue(exp.getMengs().size() > 0);
    assertTrue(def.getMengs().size() > 0);
    assertTrue(mengsDB.getNo(Meaning.class) > 0); //fails here
}

public void persistSynonyms(final EnumMap<Input, MemoEntity> input) throws MultipleMengsException {
    final Expression def = extractExp(input, Input.definition);
    final Expression exp = extractExp(input, Input.expression);
    final MUser usr = extractUsr(input);

    beginTransaction();
    final Meaning meng = persistMeng(exp, usr, def);
    commitTransaction();
    signalContentAvailability();
    logInsertion(meng, exp, def);
}

Essentially I start and commit a transaction within the same em, but then when I come to execute the getNo() method using the same em, it doesn't find what has been committed by the previous. I don't see where's the problem. There's clearly an issue since 'local' code like em.find(..) finds the committed changes, but not the criteria query.

xagyg
  • 9,562
  • 2
  • 32
  • 29
simpatico
  • 10,709
  • 20
  • 81
  • 126

1 Answers1

7

EntityManager#getTransaction() actually returns the current resource local transaction and you cannot call EntityTransaction#begin() when a transaction is already active:

/**
* Start a resource transaction.
* @throws IllegalStateException if isActive() is true
*/
public void begin();

What you can do is create serial local transactions as hinted in the javadoc of EntityManager#getTransaction():

/**
 * Return the resource-level <code>EntityTransaction</code> object.
 * The <code>EntityTransaction</code> instance may be used serially to
 * begin and commit multiple transactions.
 * @return EntityTransaction instance
 * @throws IllegalStateException if invoked on a JTA
 *         entity manager
 */
public EntityTransaction getTransaction();

To sum up, JPA (and JTA) doesn't support nested transactions.

References

Pascal Thivent
  • 562,542
  • 136
  • 1,062
  • 1,124
  • so JPA doesn't support concurrent transaction, but only serial execution of transactions. Am I understanding correctly? If so in my application I should lock onto the transaction to guarantee serial execution. – simpatico Oct 23 '10 at 17:08
  • @simpatico JPA does support concurrent transactions. But what you're trying to do is *transactions nesting*, and this isn't supported. – Pascal Thivent Oct 23 '10 at 17:14
  • but then how do I do multiple transactions? Multiple ems? – simpatico Oct 23 '10 at 17:26
  • @simpatico If you really need that, yes. – Pascal Thivent Oct 23 '10 at 17:35
  • I've added follow-up code to the question. Is this still transaction nesting? – simpatico Oct 23 '10 at 19:59
  • @simpatico I answered the initial question and I don't have anything to add. So, sorry, but I'm not going to spend more time to decipher your follow-up code (my suggestion would be to provide a simplified example and to post *another* question). – Pascal Thivent Oct 24 '10 at 02:45