5

I have an J2EE application whose beans have container-managed EntityManager's. In long running method calls, trying to merge data throws a

RollbackException (Timed out)

I have tried using an EntityManagerFactory but it doesn't seem to be allowed:

Cannot use an EntityTransaction while using JTA

How can I run arbitrarily long processes without setting an unreasonable timeout? Can't JTA create a new transaction when needed?

Petr Mensik
  • 24,455
  • 13
  • 84
  • 111
Filipe Gomes
  • 168
  • 1
  • 10

2 Answers2

5

Following the comments to my question, this question and the documentation here, I solved the problem using a container-managed EntityManager and TransactionAttributeType annotations.

The bean method that caused the timeout now does multiple calls to a different method that handles a subtask, such as each method call executes within a different transaction. I use NOT_SUPPORTED attribute type since:

If the client is not associated with a transaction, the container does not start a new transaction before running the method.

With this arrangement, only the smaller processDoc method creates transactions that shouldn't timeout.

public class MyBean {
    @EJB
    private DocsBean docsBean;

    /**
     * This method transaction risks a timeout
     * so no transaction is created with NOT_SUPPORTED
     */
    @TransactionAttribute(TransactionAttributeType.NOT_SUPPORTED)
    public void longRunning(List<Document> docs) {
        for (Document doc : docs) {
            // a different transaction is used for each element
            docsBean.processDoc(doc);
        }
    }
}

public class DocsBean {
    /** Runs within a new transaction */
    @TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
    public void processDoc(Document document) {
        // takes some time but under the timeout
        // ...
    }
}

.

Community
  • 1
  • 1
Filipe Gomes
  • 168
  • 1
  • 10
2

What about using the UserTransaction?

@Resource
private UserTransaction tx;

@TransactionAttribute(TransactionAttributeType.NotSupported)
public void merge(SomeEntity e) {
   tx.setTransactionTimeout(60 * 1000); //one minute
   tx.begin();
   try {
      entityManager.merge(e);
      tx.commit();
   } catch(IllegalArgumentException ex) { 
       tx.rollback();
   }
}
Petr Mensik
  • 24,455
  • 13
  • 84
  • 111
  • I had tried using UserTransaction but I get "OC4J does NOT support nested transactions" exception on tx.begin(). I'm using embedded OC4J for development and OAS as production environment. – Filipe Gomes Oct 13 '14 at 15:48
  • Ok, so you could disable the bean-managed transaction in the method, see my edit – Petr Mensik Oct 13 '14 at 16:06
  • Or you could set transaction type as bean on the class level `@TransactionManagement(value=TransactionManagementType.BEAN)` – Petr Mensik Oct 13 '14 at 16:09
  • The TransactionManagement annotation is needed to avoid the _nested_ exception. This does work but one downside would be that I now need to manage transactions in the whole bean? – Filipe Gomes Oct 14 '14 at 10:06
  • How about creating a separate bean with `merge(SomeEntity e)` only and calling it from the parent bean? – wypieprz Oct 14 '14 at 10:35
  • @FilipeGomes Unfortunately you are right, this is only way how to use `UserTransaction` without firing that exception. – Petr Mensik Oct 14 '14 at 12:14