7

I've set up a JSF application on JBoss 5.0.1GA to present a list of Users in a table and allow deleting of individual users via a button next to each user.

When deleteUser is called, the call is passed to a UserDAOBean which gets an EntityManager injected from JBoss.

I'm using the code

public void delete(E entity)
{
    em.remove(em.merge(entity));
}

to delete the user (code was c&p from a JPA tutorial). Just calling em.remove(entity) has no effect and still causes the same exception.

When this line is reached, I'm getting a TransactionRequiredException:

(skipping apparently irrelevant stacktrace-stuff)

...

20:38:06,406 ERROR [[Faces Servlet]] Servlet.service() for servlet Faces Servlet threw exception javax.persistence.TransactionRequiredException: EntityManager must be access within a transaction at org.jboss.jpa.deployment.ManagedEntityManagerFactory.verifyInTx(ManagedEntityManagerFactory.java:155) at org.jboss.jpa.tx.TransactionScopedEntityManager.merge(TransactionScopedEntityManager.java:192) at at.fhj.itm.utils.DAOImplTemplate.delete(DAOImplTemplate.java:54) at at.fhj.itm.UserBean.delete(UserBean.java:53) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)

...

I already tried to wrap a manually managed transaction (em.getTransaction().begin() + .commit() ) around it, but this failed because it is not allowed within JBoss container. I had no success with UserTransaction either. Searches on the web for this issue also turned up no similar case and solution.

Has anyone experienced something similar before and found a solution to this?

Kosi2801
  • 22,222
  • 13
  • 38
  • 45
  • "I already tried to wrap a transaction around it, but this failed because it is not allowed within JBoss container." - what's not allowed? Transactions? Not true. Please update and explain this more fully. – duffymo Jul 05 '09 at 19:49
  • And why do you think it's necessary to merge before removing an object? If anything's wrong, I'd disagree with that. – duffymo Jul 05 '09 at 19:50
  • Clarified (I hope). I meant manually managing transactions on the EntityManager. Furthermore the remove(merge()) is present in examples all over the web (even for Oracle). Nevertheless, tried a simple remove which still causes the same exception. – Kosi2801 Jul 05 '09 at 21:06
  • I don't think I'd recommend that merge. Take it out and see if your situation improves. – duffymo Jul 05 '09 at 21:21

4 Answers4

8

Found the missing link.

It was indeed a missing transaction but the solution was not to use the EntityManager to handle it but to add an injected UserTransaction.

@Resource
UserTransaction ut;
...
public void delete(E entity)
{
        ut.begin();
        em.remove(em.merge(entity));
        ut.commit();
}

Thanks to all suggestions which somehow over 100 corners lead to this solution.

Kosi2801
  • 22,222
  • 13
  • 38
  • 45
  • 1
    It is not very good idea to control transaction manually, this is do you code more verbose, Java2EE server can do it for you. why you don't use annotations for this? –  Jul 07 '09 at 16:40
  • 1
    Because I tried. I tried very hard to find an annotation and setting which works. I tried countless variations of @Stateless, @Stateful, @Local, @Transactionattribute, etc., none of which worked and in most cases caused the EntityManager to be not injected anymore. I really have no idea, what's causing this because my previous experiences with Hibernate do exactly as you say and let the container manage the transactions. Nevertheless, it seems to be different with JPA and JSF and since this solution is easy and only used for delete and add I'll stay with it and don't spend more time on it. – Kosi2801 Jul 07 '09 at 17:28
2

Know this is an old question, but just in case somebody stumbles on this like me.

Try

em.joinTransaction();
em.remove(bean);
em.flush();

That's what we use in all our @Stateful beans.

If you are using Seam, you can also use @Transactional(TransactionPropagationType.REQUIRED) annotation.

chinto
  • 1,486
  • 17
  • 27
1

Are you sure that you annotated you bean with @Stateless or register it with xml?

Try add transaction's annotation to you code, this can help you:

@TransactionAttribute(REQUIRED)
public void delete(E entity)
{
        em.remove(em.merge(entity));
}

But it seems strange, because this is default value if you don't set it explicitly.

  • No luck with that @TransactionAttribute either :( The bean is NOT annotated with @Stateless but the EntityManager is with @PersistenceContext(unitName = "test). When I add the @Stateless to the class, the EntityManager is not injected anymore but null. – Kosi2801 Jul 06 '09 at 10:58
  • EJB automatically creates a transaction at the beginning of any EJBean method call. Therefore, if you are not using an EJB (either `@Stateless`, `@Local`, etc. with the associated container) you will need to create your own transaction. – Drew Jul 06 '09 at 14:19
  • If you want that you bean was DAO it is be better if you annotate it with @Stateless, and use @Local interface for it. Because if if bean is not @Stateless or @Statefull then it is not EJB bean, and transaction is not managed as say Drew. Also if you new in EJB take a look at his book "Enterprise JavaBeans, 3.0" By Bill Burke, Richard Monson-Haefel –  Jul 06 '09 at 19:09
  • +1 for Are you sure that you annotated you bean with @Stateless or register it with xml? – Koray Tugay Jul 20 '13 at 20:34
0

just a note: we ran into this same issue today, turned out someone had marked the EJB as TransactionAttributeType.NOT_SUPPORTED AND the method as TransactionAttributeType.REQUIRED, causing the em.merge to fail for lack of transaction.

jwenting
  • 5,505
  • 2
  • 25
  • 30