0

I have a situation where I need to perform some work in a global tx.

For this reason, i have the following PersistenceUnit defined in my persistence.xml to get me a jta entityManager.

<persistence-unit name="resubEclipselink" transaction-type="JTA">
    <jta-data-source>jdbc/XADataSource</jta-data-source>
    ...
</persistence-unit>

Now to persist I tried to proceed as follows #1:

    if(isXA()){
        mXAEntityManager.persist(entity);
        mXAEntityManager.flush(); 
    }

Things fail with an exception

javax.persistence.TransactionRequiredException: 
Exception Description: No transaction is currently active
    at       
org.eclipse.persistence.internal.jpa.transaction.EntityTransactionWrapper.throwCheckTransactionFailedException(EntityTransactionWrapper.java:113)

I got the same reason when I begin a user transaction before proceeding.

So I tried another approach #2:

// get the transactional unit of work or null.
UnitOfWork uow = mEntityManager.getUnitOfWork();
    uow.registerObject(entity);
uow.writeChanges(); 
uow.commit();           

This sort of works but I am not sure if this is the right approach.

Will appreciate if someone can help me with why things don't work in the first case and if the second approach is fine?

Anuj Kaushal
  • 61
  • 1
  • 6

3 Answers3

2

The first approach should work, a configuration setting is likely missing telling Eclipselink about the transaction. Check that you have specified the target server property described here http://eclipse.org/eclipselink/documentation/2.4/jpa/extensions/p_target_server.htm As this will be used to get the transaction manager and register with active transactions.

Once correctly registered with the transaction, there should be no need to call commit on a UnitOfWork directly.

Chris
  • 20,138
  • 2
  • 29
  • 43
1

I assume that earlier in your code you instantiated mXAEntityManager the SE way like this:

EntityManagerFactory entityManagerFactory = Persistence.createEntityManagerFactory("resubEclipselink");

EntityManager mXAEntityManager = entityManagerFactory.createEntityManager();

which does not work in an EE application deployed in an application server. You should replace those 2 lines with dependency injection like this:

@PersistenceContext(unitName = "resubEclipselink")

EntityManager mXAEntityManager;

so that you allow the container to inject a persistence context (mXAEntityManager) accompanied with all the transaction management you need. Thus no flush() no begin() no commit() calls will be needed any more, as long as you don't mess with the default which is already set to be like this:

@PersistenceContext(unitName = "resubEclipselink", type= PersistenceContextType.TRANSACTION)

EntityManager mXAEntityManager;

As well as another default already set for your session bean like this:

@TransactionAttribute(TransactionAttributeType.REQUIRED)

Remember these default is what makes developing an EE application following the paradigm "Configuration by Exception".

Community
  • 1
  • 1
Sym-Sym
  • 3,578
  • 1
  • 29
  • 30
  • Thanks for the explanation and that's exactly the thing I am doing to acquire an entityManager. Now I understand, that I probably need a container-managed entity manager and that it should be acquired the way you suggested. But unfortunately my scenario runs in a way where I need to decide the transaction boundary based on some other conditions. Also I get the call through a facade api which is not really in my control so injecting through a session bean may not be too feasible for me. – Anuj Kaushal Nov 05 '12 at 07:18
0

my scenario runs in a way where I need to decide the transaction boundary based on some other conditions.

So basically I need to have my application-managed entity manager enlist onto the global tx and perform some unit of work as part of the global tx. So I actually get an entity manager and set it to use the ExternalTransactionController.

            if(isXA){
                    this.mEntityManager = JpaHelper.getEntityManager(Persistence.createEntityManagerFactory(XA_PU).

                                            createEntityManager());

                    this.mServerSession = this.mEntityManager.getServerSession();
                    this.mServerSession.getLogin().setUsesExternalTransactionController(true);
                    this.mServerSession.getLogin().setUsesExternalConnectionPooling(true);
            }else{
                   this.mEntityManager = JpaHelper.getEntityManager(Persistence.createEntityManagerFactory(RESORUCE_LOCAL_PU).
                                                                                                                            createEntityManager());

                    this.mEntityTransaction = this.mEntityManager.getTransaction();
                    this.mServerSession = this.mEntityManager.getServerSession();
            }

and then acquire and perform the unit of work as...

  // get the transactional unit of work or null.
  UnitOfWork uow = mEntityManager.getUnitOfWork();

  // resource-local em
  if(uow == null){
          mEntityTransaction.begin(); 
          mEntityManager.persist(entity); 
          mEntityTransaction.commit();
  }else{                  
          uow.registerObject(entity);
          uow.writeChanges(); 
          uow.commit();                   
  }

As I mentioned before, I am not too confident about this approach and so will really appreciate if someone can review this and let me know if this approach has some flaws...

Anuj Kaushal
  • 61
  • 1
  • 6